home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D+,L+,N-,E-,O-,R-,S-,V-,G-,F-,I-,X-}
- {$M 16384,0,655360}
- {$UNDEF IOcheck}
-
- {Programmtool zur Realisierung schneller Animationen auf der VGA-Grafik- }
- {karte von: Kai Rohrbacher, 1988-1993, Turbo-Pascal 6.0 }
-
- { Features: }
-
- { - flickerfreie Animation durch page-flipping, Auswertung von Retrace- }
- { signalen und Verwendung eines speziellen VGA-256-Farbengrafikmodus }
- { - Spritebewegung pixelweise (und nicht nur byteweise) möglich }
- { - beliebiges Hintergrundbild, vor der die Animation geschieht }
- { - Animationen können auf ein Bildschirmfenster begrenzt werden }
- { - volle Unterstützung der 256-Farbmöglichkeiten der VGA-Karte }
- { - verschiedene Spritedarstellungsmöglichkeiten: }
- { - Sprites können pixelweise als durchsichtig gegenüber dem Hintergrund }
- { deklariert werden }
- { - Sprites können ihre Farbe in Abhängigkeit ihres momentanen Hinter- }
- { grundes verändern ("Schattenfunktion") }
- { - Routine zur exakten Feststellung der Kollision zweier Sprites }
- { - Sprites werden beim Verschwinden an einer der Bildschirmgrenzen korrekt }
- { abgeschnitten }
- { - Verwaltung von bis zu 32767 verschiedenen Sprites (Voreinstellung: 1000)}
- { - gleichzeitige Darstellung von bis zu 32767 Sprites (Voreinstellung: 500)}
- { - maximale Spritegröße 64k }
- { - maximaler Umfang aller Sprites zusammen nur durch Hauptspeicher begrenzt}
- { - arbeitet mit virtuellen Koordinaten im Bereich -16000..+16000, daher }
- { einfaches horizontales und vertikales Scrolling möglich }
- { - Scrollbares Hintergrundbild ebenfalls unterstützt }
- { - Einschränkung der Animation auf ein Window ist möglich }
- { - viele unterstützende Routinen: zeichnen von Linien (mit eingebautem }
- { Clipping-Algorithmus), Punkten und Grafik-Text (dto.), automatische Ver-}
- { waltungs des Heaps zum Speichern/Laden von Sprites, Hintergrundbildern, }
- { Ändern von Spritedarstellungsmodi während der Laufzeit, Geschwindig- }
- { keitsanpassung an unterschiedlich schnelle Rechner, ... }
-
- UNIT ANIVGA;
- INTERFACE
-
- USES CRT,DOS,Compression;
-
- CONST ANIVGAVersion=12; {Versionsnummer}
- NMAX=499;
- XMAX=319;
- YMAX=199;
- LoadMAX=1000; {max. Anzahl an gleichzeitig geladenenen Sprites}
- LINESIZE=(XMAX+1) DIV 4; {Größe einer Zeile = 80 Bytes}
- PAGESIZE=(YMAX+1)*LINESIZE; {200 Zeilen zu je 320/4 Bytes}
- BACKGNDPAGE=2;
- SCROLLPAGE=3;
-
- STATIC=0; {Konstanten für Hintergrundart}
- SCROLLING=1;
-
- MaxTiles=10000; {max. Anzahl an Hintergrund-Kacheln}
- StartVirtualX:INTEGER=0; {obere linke Bildschirmecke}
- StartVirtualY:INTEGER=0;
-
- {unterstützte Darstellungsmodi der Sprites: }
- Display_NORMAL=0; {normal : durchsichtig für Farbe 0}
- Display_FAST =1; {schnell : keine Hintergrundberücksichtigung}
- Display_SHADOW=2; {Schatten: Farbumsetzung anhand des Hintergrundes}
- Display_SHADOWEXACT=3; {Farbe 0 ist auch für Schatten durchsichtig}
- Display_UNKNOWN=255;{Fehlerwert}
-
- {Fehlercodes des Animationspaketes: }
- Err_None=0;
- Err_NotEnoughMemory=1;
- Err_FileIO=2;
- Err_InvalidSpriteNumber=3;
- Err_NoSprite=4;
- Err_InvalidPageNumber=5;
- Err_NoVGA=6;
- Err_NoPicture=7;
- Err_InvalidPercentage=8;
- Err_NoTile=9;
- Err_InvalidTileNumber=10;
- Err_InvalidCoordinates=11;
- Err_BackgroundToBig=12;
- Err_InvalidMode=13;
- Err_InvalidSpriteLoadNumber=14;
- Err_NoPalette=15;
- Err_PaletteWontFit=16;
- Err_InvalidFade=17;
- Err_NoFont=18;
- Err_EMSError=19;
-
- CONST MaxFontHeight=16;
- MaxFontWidth=15;
- TagMonoFont=0;
- TagColorFont=1;
- TagProportional=$80;
- TYPE MonoFontChar=ARRAY[0..MaxFontHeight-1] OF WORD;
- MonoFont=ARRAY[0..255] OF MonoFontchar;
- ColorFontChar=ARRAY[0..MaxFontHeight-1] OF ARRAY[0..MaxFontWidth-1] OF BYTE;
- ColorFont=ARRAY[0..255] OF ColorFontchar;
- FontOrient=(horizontal,vertical); {mögliche Textausgaberichtungen}
- CONST GraphTextOrientation:FontOrient=horizontal; {aktuelle Ausgaberichtung}
- GraphTextColor:BYTE=white; {aktuelle Textausgabefarben}
- GraphTextBackground:BYTE=white;
- CurrentFont:POINTER=NIL; {Zeiger auf aktuellen Font}
- UpdateOuterArea:BYTE=2; {äußeren Hintergrund updaten}
- WinClip:BOOLEAN=FALSE; {Pixel auf Fenster clippen?}
- VAR FontHeight,
- FontWidth,
- FontType,
- FontProportion:BYTE;
- FontWidthTable:ARRAY[0..255] OF BYTE;
-
- TYPE Table=ARRAY[0..NMAX] OF INTEGER;
- ColorTable=ARRAY[0..255] OF BYTE;
-
- TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
- Palette=ARRAY[0..255] OF PaletteEntry;
- PalettePtr=^Palette;
-
- CONST DefaultColors:Palette= {Defaultfarben-Palette des 256-Farbmodus}
- ( {ausgelesen mithilfe des BIOS-Aufrufs: }
- (red: 0; green: 0; blue: 0), { MOV AX,1017h ;lese Palettenregister}
- (red: 0; green: 0; blue: 42), { XOR BX,BX ;von Farbe 0 an }
- (red: 0; green: 42; blue: 0), { MOV CX,100h ;alle 256 Farben}
- (red: 0; green: 42; blue: 42), { LES DX,Ziel ;nach ES:DX }
- (red: 42; green: 0; blue: 0), { INT 10h }
- (red: 42; green: 0; blue: 42), {Achtung! Die Werte könn(t)en nur dann }
- (red: 42; green: 21; blue: 0), {ausgelesen werden, wenn der Grafikmodus}
- (red: 42; green: 42; blue: 42), {bereits aktiv ist, deshalb wurden sie }
- (red: 21; green: 21; blue: 21), {hier "statisch" aufgenommen!}
- (red: 21; green: 21; blue: 63),
- (red: 21; green: 63; blue: 21),
- (red: 21; green: 63; blue: 63),
- (red: 63; green: 21; blue: 21),
- (red: 63; green: 21; blue: 63),
- (red: 63; green: 63; blue: 21),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 0),
- (red: 5; green: 5; blue: 5),
- (red: 8; green: 8; blue: 8),
- (red: 11; green: 11; blue: 11),
- (red: 14; green: 14; blue: 14),
- (red: 17; green: 17; blue: 17),
- (red: 20; green: 20; blue: 20),
- (red: 24; green: 24; blue: 24),
- (red: 28; green: 28; blue: 28),
- (red: 32; green: 32; blue: 32),
- (red: 36; green: 36; blue: 36),
- (red: 40; green: 40; blue: 40),
- (red: 45; green: 45; blue: 45),
- (red: 50; green: 50; blue: 50),
- (red: 56; green: 56; blue: 56),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 63),
- (red: 16; green: 0; blue: 63),
- (red: 31; green: 0; blue: 63),
- (red: 47; green: 0; blue: 63),
- (red: 63; green: 0; blue: 63),
- (red: 63; green: 0; blue: 47),
- (red: 63; green: 0; blue: 31),
- (red: 63; green: 0; blue: 16),
- (red: 63; green: 0; blue: 0),
- (red: 63; green: 16; blue: 0),
- (red: 63; green: 31; blue: 0),
- (red: 63; green: 47; blue: 0),
- (red: 63; green: 63; blue: 0),
- (red: 47; green: 63; blue: 0),
- (red: 31; green: 63; blue: 0),
- (red: 16; green: 63; blue: 0),
- (red: 0; green: 63; blue: 0),
- (red: 0; green: 63; blue: 16),
- (red: 0; green: 63; blue: 31),
- (red: 0; green: 63; blue: 47),
- (red: 0; green: 63; blue: 63),
- (red: 0; green: 47; blue: 63),
- (red: 0; green: 31; blue: 63),
- (red: 0; green: 16; blue: 63),
- (red: 31; green: 31; blue: 63),
- (red: 39; green: 31; blue: 63),
- (red: 47; green: 31; blue: 63),
- (red: 55; green: 31; blue: 63),
- (red: 63; green: 31; blue: 63),
- (red: 63; green: 31; blue: 55),
- (red: 63; green: 31; blue: 47),
- (red: 63; green: 31; blue: 39),
- (red: 63; green: 31; blue: 31),
- (red: 63; green: 39; blue: 31),
- (red: 63; green: 47; blue: 31),
- (red: 63; green: 55; blue: 31),
- (red: 63; green: 63; blue: 31),
- (red: 55; green: 63; blue: 31),
- (red: 47; green: 63; blue: 31),
- (red: 39; green: 63; blue: 31),
- (red: 31; green: 63; blue: 31),
- (red: 31; green: 63; blue: 39),
- (red: 31; green: 63; blue: 47),
- (red: 31; green: 63; blue: 55),
- (red: 31; green: 63; blue: 63),
- (red: 31; green: 55; blue: 63),
- (red: 31; green: 47; blue: 63),
- (red: 31; green: 39; blue: 63),
- (red: 45; green: 45; blue: 63),
- (red: 49; green: 45; blue: 63),
- (red: 54; green: 45; blue: 63),
- (red: 58; green: 45; blue: 63),
- (red: 63; green: 45; blue: 63),
- (red: 63; green: 45; blue: 58),
- (red: 63; green: 45; blue: 54),
- (red: 63; green: 45; blue: 49),
- (red: 63; green: 45; blue: 45),
- (red: 63; green: 49; blue: 45),
- (red: 63; green: 54; blue: 45),
- (red: 63; green: 58; blue: 45),
- (red: 63; green: 63; blue: 45),
- (red: 58; green: 63; blue: 45),
- (red: 54; green: 63; blue: 45),
- (red: 49; green: 63; blue: 45),
- (red: 45; green: 63; blue: 45),
- (red: 45; green: 63; blue: 49),
- (red: 45; green: 63; blue: 54),
- (red: 45; green: 63; blue: 58),
- (red: 45; green: 63; blue: 63),
- (red: 45; green: 58; blue: 63),
- (red: 45; green: 54; blue: 63),
- (red: 45; green: 49; blue: 63),
- (red: 0; green: 0; blue: 28),
- (red: 7; green: 0; blue: 28),
- (red: 14; green: 0; blue: 28),
- (red: 21; green: 0; blue: 28),
- (red: 28; green: 0; blue: 28),
- (red: 28; green: 0; blue: 21),
- (red: 28; green: 0; blue: 14),
- (red: 28; green: 0; blue: 7),
- (red: 28; green: 0; blue: 0),
- (red: 28; green: 7; blue: 0),
- (red: 28; green: 14; blue: 0),
- (red: 28; green: 21; blue: 0),
- (red: 28; green: 28; blue: 0),
- (red: 21; green: 28; blue: 0),
- (red: 14; green: 28; blue: 0),
- (red: 7; green: 28; blue: 0),
- (red: 0; green: 28; blue: 0),
- (red: 0; green: 28; blue: 7),
- (red: 0; green: 28; blue: 14),
- (red: 0; green: 28; blue: 21),
- (red: 0; green: 28; blue: 28),
- (red: 0; green: 21; blue: 28),
- (red: 0; green: 14; blue: 28),
- (red: 0; green: 7; blue: 28),
- (red: 14; green: 14; blue: 28),
- (red: 17; green: 14; blue: 28),
- (red: 21; green: 14; blue: 28),
- (red: 24; green: 14; blue: 28),
- (red: 28; green: 14; blue: 28),
- (red: 28; green: 14; blue: 24),
- (red: 28; green: 14; blue: 21),
- (red: 28; green: 14; blue: 17),
- (red: 28; green: 14; blue: 14),
- (red: 28; green: 17; blue: 14),
- (red: 28; green: 21; blue: 14),
- (red: 28; green: 24; blue: 14),
- (red: 28; green: 28; blue: 14),
- (red: 24; green: 28; blue: 14),
- (red: 21; green: 28; blue: 14),
- (red: 17; green: 28; blue: 14),
- (red: 14; green: 28; blue: 14),
- (red: 14; green: 28; blue: 17),
- (red: 14; green: 28; blue: 21),
- (red: 14; green: 28; blue: 24),
- (red: 14; green: 28; blue: 28),
- (red: 14; green: 24; blue: 28),
- (red: 14; green: 21; blue: 28),
- (red: 14; green: 17; blue: 28),
- (red: 20; green: 20; blue: 28),
- (red: 22; green: 20; blue: 28),
- (red: 24; green: 20; blue: 28),
- (red: 26; green: 20; blue: 28),
- (red: 28; green: 20; blue: 28),
- (red: 28; green: 20; blue: 26),
- (red: 28; green: 20; blue: 24),
- (red: 28; green: 20; blue: 22),
- (red: 28; green: 20; blue: 20),
- (red: 28; green: 22; blue: 20),
- (red: 28; green: 24; blue: 20),
- (red: 28; green: 26; blue: 20),
- (red: 28; green: 28; blue: 20),
- (red: 26; green: 28; blue: 20),
- (red: 24; green: 28; blue: 20),
- (red: 22; green: 28; blue: 20),
- (red: 20; green: 28; blue: 20),
- (red: 20; green: 28; blue: 22),
- (red: 20; green: 28; blue: 24),
- (red: 20; green: 28; blue: 26),
- (red: 20; green: 28; blue: 28),
- (red: 20; green: 26; blue: 28),
- (red: 20; green: 24; blue: 28),
- (red: 20; green: 22; blue: 28),
- (red: 0; green: 0; blue: 16),
- (red: 4; green: 0; blue: 16),
- (red: 8; green: 0; blue: 16),
- (red: 12; green: 0; blue: 16),
- (red: 16; green: 0; blue: 16),
- (red: 16; green: 0; blue: 12),
- (red: 16; green: 0; blue: 8),
- (red: 16; green: 0; blue: 4),
- (red: 16; green: 0; blue: 0),
- (red: 16; green: 4; blue: 0),
- (red: 16; green: 8; blue: 0),
- (red: 16; green: 12; blue: 0),
- (red: 16; green: 16; blue: 0),
- (red: 12; green: 16; blue: 0),
- (red: 8; green: 16; blue: 0),
- (red: 4; green: 16; blue: 0),
- (red: 0; green: 16; blue: 0),
- (red: 0; green: 16; blue: 4),
- (red: 0; green: 16; blue: 8),
- (red: 0; green: 16; blue: 12),
- (red: 0; green: 16; blue: 16),
- (red: 0; green: 12; blue: 16),
- (red: 0; green: 8; blue: 16),
- (red: 0; green: 4; blue: 16),
- (red: 8; green: 8; blue: 16),
- (red: 10; green: 8; blue: 16),
- (red: 12; green: 8; blue: 16),
- (red: 14; green: 8; blue: 16),
- (red: 16; green: 8; blue: 16),
- (red: 16; green: 8; blue: 14),
- (red: 16; green: 8; blue: 12),
- (red: 16; green: 8; blue: 10),
- (red: 16; green: 8; blue: 8),
- (red: 16; green: 10; blue: 8),
- (red: 16; green: 12; blue: 8),
- (red: 16; green: 14; blue: 8),
- (red: 16; green: 16; blue: 8),
- (red: 14; green: 16; blue: 8),
- (red: 12; green: 16; blue: 8),
- (red: 10; green: 16; blue: 8),
- (red: 8; green: 16; blue: 8),
- (red: 8; green: 16; blue: 10),
- (red: 8; green: 16; blue: 12),
- (red: 8; green: 16; blue: 14),
- (red: 8; green: 16; blue: 16),
- (red: 8; green: 14; blue: 16),
- (red: 8; green: 12; blue: 16),
- (red: 8; green: 10; blue: 16),
- (red: 11; green: 11; blue: 16),
- (red: 12; green: 11; blue: 16),
- (red: 13; green: 11; blue: 16),
- (red: 15; green: 11; blue: 16),
- (red: 16; green: 11; blue: 16),
- (red: 16; green: 11; blue: 15),
- (red: 16; green: 11; blue: 13),
- (red: 16; green: 11; blue: 12),
- (red: 16; green: 11; blue: 11),
- (red: 16; green: 12; blue: 11),
- (red: 16; green: 13; blue: 11),
- (red: 16; green: 15; blue: 11),
- (red: 16; green: 16; blue: 11),
- (red: 15; green: 16; blue: 11),
- (red: 13; green: 16; blue: 11),
- (red: 12; green: 16; blue: 11),
- (red: 11; green: 16; blue: 11),
- (red: 11; green: 16; blue: 12),
- (red: 11; green: 16; blue: 13),
- (red: 11; green: 16; blue: 15),
- (red: 11; green: 16; blue: 16),
- (red: 11; green: 15; blue: 16),
- (red: 11; green: 13; blue: 16),
- (red: 11; green: 12; blue: 16),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0)
- );
-
- VAR Error:BYTE; {globale Fehlervariable}
- SpriteN:Table;
- SpriteX:Table;
- SpriteY:Table;
- NextSprite:ARRAY[0..LoadMAX] OF WORD;
- PAGE,PAGEADR,SCROLLADR,BACKGNDADR:WORD;
- Color:BYTE; {Zeichenfarbe für Linien}
- ActualColors:Palette; {aktuelle Farbpalette}
- was_cut:BOOLEAN; {TRUE/FALSE, falls "GetImage" clippen mußte }
- left_cut, {Var., die durch "GetImage" gesetzt werden und}
- right_cut, {bei "was_cut"=TRUE darüber Auskunft geben, }
- top_cut, {wo und wieviel des Bildes abgeschnitten }
- bottom_cut:WORD; {werden mußte }
-
- WinXMIN,WinYMIN,WinXMAX,WinYMAX,WinWidth,WinHeight:WORD;
-
- BackgroundMode:BYTE;
- BackTile:ARRAY[0..MaxTiles] OF BYTE; {Kachelnspeicher}
- XTiles,YTiles:INTEGER; {Breite,Höhe des def. Bereiches }
- BackX1,BackY1,BackX2,BackY2:INTEGER; {Koordinaten des def. Bereiches }
-
- CONST Fade_Squares =0;
- Fade_Moiree1 =1;
- Fade_Moiree2 =2;
- Fade_Moiree3 =3;
- Fade_Moiree4 =4;
- Fade_Moiree5 =5;
- Fade_Moiree6 =6;
- Fade_Moiree7 =7;
- Fade_Moiree8 =8;
- Fade_Moiree9 =9;
- Fade_Moiree10=10;
- Fade_Moiree11=11;
- Fade_Moiree12=12;
- Fade_Moiree13=13;
- Fade_Moiree14=14;
- Fade_SweepInFromTop=15;
- Fade_SweepInFromBottom=16;
- Fade_SweepInFromLeft=17;
- Fade_SweepInFromRight=18;
- Fade_ScrollInFromTop=19;
- Fade_ScrollInFromBottom=20;
- Fade_ScrollInFromLeft=21;
- Fade_ScrollInFromRight=22;
- Fade_Circles =23;
- Fade_Moiree15=24;
-
- {---- für EMS-Routinen ----}
-
- CONST BACKTAB:ARRAY[0..3] OF WORD=(0,PAGESIZE,2*PAGESIZE,3*PAGESIZE);
- TYPE Puffer=ARRAY[0..4*PAGESIZE-1 +15] OF BYTE; {Puffer für eine Seite}
- VAR buf:^Puffer; {Zeiger darauf}
-
- Const EMSInt = $67; {für EMS benutzter Interrupt}
- USEEMS = TRUE; {bei FALSE: keine Nutzung von vorhandenem EMS,}
- {bei TRUE : Nutzung, wenn vorhanden}
-
- Var EMSError:BYTE; {<>0 heißt: es trat ein Fehler auf }
- BackgroundEMSHandle:WORD; {Zugriffshandle auf allozierten EMS-Block}
- EMSused:BOOLEAN; {zeigt an, ob tatsächlich EMS verwendet wird}
-
- PROCEDURE ShadowTab;
- PROCEDURE SetShadowTab(brightness:BYTE);
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- PROCEDURE GetPalette(VAR pal:Palette);
- PROCEDURE FadeToPalette(destPal:Palette; AnzSteps:WORD);
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- PROCEDURE EnsureEMSConsistency(EMSHandle:WORD);
- PROCEDURE SetCycleTime(milliseconds:WORD);
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:WORD):POINTER;
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:WORD);
- PROCEDURE FreeImageMem(p:POINTER);
- PROCEDURE InitGraph;
- PROCEDURE Screen(pa:WORD);
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:WORD);
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- FUNCTION GetPixel(x,y:INTEGER):BYTE;
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE;
- FUNCTION PageGetPixel(x,y:INTEGER; pa:WORD):BYTE;
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE PagePutPixel(x,y:INTEGER; color:BYTE; pa:WORD);
- PROCEDURE LoadFont(s:STRING);
- FUNCTION OutTextLength(s:STRING):WORD;
- PROCEDURE OutTextXY(x,y:INTEGER; pa:WORD; s:STRING);
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- PROCEDURE MakeTextSprite(s:STRING; nr:WORD);
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN;
- PROCEDURE SetSplitIndex(number:INTEGER);
- FUNCTION GetSplitIndex:INTEGER;
- PROCEDURE SetAnimateWindow(x1,y1,x2,y2:INTEGER);
- PROCEDURE Animate;
- PROCEDURE FreeSpriteMem(number:WORD);
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- PROCEDURE SetBackgroundMode(mode:BYTE);
- PROCEDURE MakeTileArea(FirstTile:BYTE; TileWidth,TileHeight:INTEGER);
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- FUNCTION GetTile(x,y:INTEGER):BYTE;
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- PROCEDURE FillPage(pa:WORD; color:Byte);
- PROCEDURE FillBackground(color:BYTE);
- PROCEDURE GetBackgroundFromPage(pa:WORD);
- PROCEDURE WritePage(name:STRING; pa:WORD);
- PROCEDURE LoadPage(name:STRING; pa:WORD);
- PROCEDURE WriteBackgroundPage(name:STRING);
- PROCEDURE LoadBackgroundPage(name:STRING);
- PROCEDURE FadeIn(pa,ti,style:WORD);
- PROCEDURE CopyVRAMtoVRAM(source,dest:POINTER; len:WORD);
- PROCEDURE IntroScroll(n,wait:WORD);
- PROCEDURE InitRoutines;
- PROCEDURE CloseRoutines;
- FUNCTION GetErrorMessage:STRING;
- FUNCTION FindFile(P:PathStr):PathStr;
-
- {--------------------------------------------------------------------------}
-
- IMPLEMENTATION
-
- CONST ANIVGAVersionS:STRING[11]='AniVGA V1.2'; {Versionsnummer}
- StartIndex=0;
- EndIndex=StartIndex+3;
- {Offsetadressen der Grafikseiten (in Segment $A000):}
- Offset_Adr:Array[StartIndex..EndIndex] OF WORD=($0000,$3E80,$7D00,$BB80);
- {Segmentadressen der Grafikseiten (bei Offset = 0) :}
- Segment_Adr:ARRAY[StartIndex..EndIndex] OF WORD=($A000,$A3E8,$A7D0,$ABB8);
-
- {Sprite(header)aufbau: }
-
- {0..1 DW Plane_0_Daten}
- {2..3 DW Plane_1_Daten}
- {4..5 DW Plane_2_Daten}
- {6..7 DW Plane_3_Daten}
- {8..9 DW Breite (in 4er-Gruppen)}
- {10..11 DW Höhe in Zeilen}
- {12..15 DB 1,2,4,8 ; Translate-Tabelle für Port-Ansteuerung}
- {16..17 DW SpriteLength ; Länge der Spritedatei}
- { ; jetzt für temporäre Variablen reservierter}
- { ; Bereich:}
- {18..19 DW ? ; licutoff_ | hit1xfirst}
- {20..21 DW ? ; zeilenadr | hit1yfirst}
- {22..23 DW ? ; bildx | hit2xfirst}
- {24..25 DW ? ; yoffset_ | hit2yfirst}
- {26..27 DW ? ; end_min_start | ueberlappx_1}
- {28..29 DW ? ; WinXMIN_ | ueberlappy_1}
- {30..31 DW ? ; WinXMAX_ | x1}
- {32..33 DW ? ; WinYMIN_ | x2}
- {34..35 DW ? ; | y1}
- {36..37 DW ? ; | y2}
- {38..39 DB 'K','R' ; Kennung als Sprite}
- {40 DB 1 ; Versionsnummer}
- {41 DB 0 ; Modusnummer für Sprite}
- {42..43 DW linke_Begrenzungen }
- {44..45 DW rechte_Begrenzungen}
- {46..47 DW obere_Begrenzungen }
- {48..49 DW untere_Begrenzungen}
- {50..?? DB Daten}
-
- {zum Bsp.: xxrxxxxx, mit: r=rot=40, g=grün=45, b=blau=35, x=weiß=30}
- { xrgrxxxx}
- { rbgbrxxx}
-
- {Adressen von wichtigen Werten innerhalb des Spriteheaders:}
- Left=42;
- Right=44;
- Top=46;
- Bottom=48;
- Breite=8;
- Hoehe=10;
- Translate=12;
- SpriteLength=16;
- Kennung=38;
- Version=40;
- Modus=41;
-
- {Adressen der temporären Variablen für die Zeichenroutinen:}
- licutoff_=18;
- zeilenadr=20;
- bildx=22;
- yoffset_=24;
- end_min_start=26;
- WinXMIN_=28;
- WinXMAX_=30;
- WinYMIN_=32;
-
- {Adressen der temporären Variablen für die Kollisionsprüfroutine:}
- hit1xfirst=18;
- hit1yfirst=20;
- hit2xfirst=22;
- hit2yfirst=24;
- ueberlappx_1=26;
- ueberlappy_1=28;
- x1=30;
- x2=32;
- y1=34;
- y2=36;
-
- TranslateTab:ARRAY[0..3] OF BYTE=(1,2,4,8); {Für Maskenadressierung}
- PICHeader:STRING[3]='PIC'; {Kennung in Bilderdateien}
- Schatten :BYTE=70; {Default-Helligkeit von Schatten}
-
- TYPE SpriteHeader= RECORD
- Zeiger_auf_Plane:Array[0..3] OF Word;
- Breite_in_4er_Gruppen:WORD;
- Hoehe_in_Zeilen:WORD;
- Translate:Array[1..4] OF Byte;
- SpriteLength:WORD;
- Dummy:Array[1..10] OF Word;
- Kennung:ARRAY[1..2] OF CHAR;
- Version:BYTE;
- Modus:BYTE;
- ZeigerL,ZeigerR,ZeigerO,ZeigerU:Word;
- END;
-
- CONST Kopf=SizeOf(SpriteHeader);
- FontMask:ARRAY[0..MaxFontWidth-1] OF WORD=
- ($4000,$2000,$1000,$800,$400,$200,$100,$80,$40,$20,$10,8,4,2,1);
- internalFont:ARRAY[0..255,0..5] OF BYTE= {verwendeter Zeichensatz: }
- (( 0, 0, 0, 0, 0, 0), {#0} {selbstgestrickter 6x6 Font}
- ( 0, 54, 0, 62, 28, 0), {#1}
- ( 62, 42, 62, 34, 54, 62), {#2}
- ( 0, 20, 62, 62, 28, 8), {#3}
- ( 0, 8, 28, 62, 28, 8), {#4}
- ( 8, 28, 54, 62, 8, 28), {#5}
- ( 8, 28, 62, 62, 8, 28), {#6}
- ( 0, 8, 54, 54, 8, 0), {#7}
- ( 62, 54, 42, 42, 54, 62), {#8}
- ( 0, 28, 50, 38, 28, 0), {#9}
- ( 62, 34, 42, 42, 34, 62), {#10}
- ( 14, 6, 8, 28, 34, 28), {#11}
- ( 28, 34, 28, 8, 62, 8), {#12}
- ( 14, 10, 8, 8, 56, 56), {#13}
- ( 0, 30, 18, 30, 18, 54), {#14}
- ( 0, 8, 42, 20, 42, 8), {#15}
- ( 0, 32, 56, 62, 56, 32), {#16}
- ( 0, 2, 14, 62, 14, 2), {#17}
- ( 8, 28, 42, 42, 28, 8), {#18}
- ( 0, 54, 54, 54, 0, 54), {#19}
- ( 0, 30, 42, 26, 10, 10), {#20}
- ( 6, 8, 4, 10, 36, 24), {#21}
- ( 0, 0, 0, 0, 62, 62), {#22}
- ( 8, 28, 8, 28, 8, 62), {#23}
- ( 0, 8, 28, 62, 8, 8), {#24}
- ( 0, 8, 8, 62, 28, 8), {#25}
- ( 0, 8, 4, 62, 4, 8), {#26}
- ( 0, 8, 16, 62, 16, 8), {#27}
- ( 0, 0, 48, 62, 0, 0), {#28}
- ( 0, 0, 20, 62, 20, 0), {#29}
- ( 0, 0, 0, 8, 28, 62), {#30}
- ( 0, 0, 62, 28, 8, 0), {#31}
- ( 0, 0, 0, 0, 0, 0), { }
- ( 0, 12, 12, 12, 0, 12), {!}
- ( 0, 20, 20, 0, 0, 0), {"}
- ( 0, 20, 62, 20, 62, 20), {#}
- ( 8, 30, 40, 28, 10, 60), { $}
- ( 0, 50, 4, 8, 16, 38), {%}
- ( 0, 28, 54, 28, 38, 26), {&}
- ( 0, 4, 8, 0, 0, 0), {'}
- ( 0, 28, 48, 48, 48, 28), {(}
- ( 0, 56, 12, 12, 12, 56), {)}
- ( 0, 20, 8, 62, 8, 20), {*}
- ( 0, 0, 8, 62, 8, 0), {+}
- ( 0, 0, 0, 8, 8, 16), {,}
- ( 0, 0, 0, 62, 0, 0), {-}
- ( 0, 0, 0, 0, 12, 0), {.}
- ( 1, 2, 4, 8, 16, 32), {/}
- ( 0, 28, 38, 42, 50, 28), {0}
- ( 0, 12, 28, 12, 12, 30), {1}
- ( 0, 60, 6, 28, 48, 62), {2}
- ( 0, 60, 6, 28, 6, 60), {3}
- ( 0, 48, 52, 62, 12, 12), {4}
- ( 0, 62, 48, 60, 6, 60), {5}
- ( 0, 62, 32, 62, 34, 62), {6}
- ( 0, 62, 6, 12, 24, 24), {7}
- ( 0, 28, 54, 28, 54, 28), {8}
- ( 0, 28, 34, 30, 2, 28), {9}
- ( 0, 0, 8, 0, 8, 0), {:}
- ( 0, 0, 8, 0, 8, 16), {;}
- ( 0, 6, 12, 24, 12, 6), {<}
- ( 0, 0, 62, 0, 62, 0), {=}
- ( 0, 24, 12, 6, 12, 24), {>}
- ( 28, 34, 4, 8, 0, 8), {?}
- ( 0, 28, 34, 46, 32, 30), {@}
- ( 0, 28, 50, 62, 50, 50), {A}
- ( 0, 60, 50, 60, 50, 60), {B}
- ( 0, 30, 48, 48, 48, 30), {C}
- ( 0, 60, 54, 50, 54, 60), {D}
- ( 0, 62, 48, 60, 48, 62), {E}
- ( 0, 62, 48, 60, 48, 48), {F}
- ( 0, 30, 48, 54, 50, 30), {G}
- ( 0, 50, 50, 62, 50, 50), {H}
- ( 0, 30, 12, 12, 12, 30), {I}
- ( 0, 62, 2, 2, 50, 28), {J}
- ( 0, 50, 52, 56, 52, 50), {K}
- ( 0, 48, 48, 48, 48, 62), {L}
- ( 0, 34, 54, 42, 34, 34), {M}
- ( 0, 34, 50, 42, 38, 34), {N}
- ( 0, 28, 50, 50, 50, 28), {O}
- ( 0, 60, 50, 60, 48, 48), {P}
- ( 0, 24, 52, 52, 52, 26), {Q}
- ( 0, 60, 34, 60, 52, 50), {R}
- ( 0, 62, 48, 62, 6, 62), {S}
- ( 0, 62, 24, 24, 24, 24), {T}
- ( 0, 50, 50, 50, 50, 62), {U}
- ( 0, 50, 50, 50, 50, 12), {V}
- ( 0, 34, 34, 42, 62, 20), {W}
- ( 0, 34, 54, 28, 54, 34), {X}
- ( 0, 50, 50, 28, 12, 12), {Y}
- ( 0, 62, 6, 28, 48, 62), {Z}
- ( 0, 30, 24, 24, 24, 30), {[}
- ( 32, 16, 8, 4, 2, 1), {\}
- ( 0, 30, 6, 6, 6, 30), {]}
- ( 8, 20, 34, 0, 0, 0), {^}
- ( 0, 0, 0, 0, 0, 62), {_}
- ( 16, 8, 0, 0, 0, 0), {`}
- ( 0, 0, 28, 50, 50, 30), {a}
- ( 0, 32, 60, 34, 34, 60), {b}
- ( 0, 0, 30, 48, 48, 30), {c}
- ( 0, 2, 30, 34, 34, 30), {d}
- ( 0, 0, 28, 62, 32, 28), {e}
- ( 0, 6, 8, 30, 8, 8), {f}
- ( 0, 28, 34, 30, 2, 28), {g}
- ( 0, 48, 60, 50, 50, 50), {h}
- ( 12, 0, 12, 12, 12, 12), {i}
- ( 6, 0, 6, 6, 54, 28), {j}
- ( 0, 48, 52, 56, 54, 54), {k}
- ( 0, 24, 24, 24, 24, 14), {l}
- ( 0, 0, 52, 62, 42, 34), {m}
- ( 0, 0, 60, 50, 50, 50), {n}
- ( 0, 0, 28, 50, 50, 28), {o}
- ( 0, 0, 60, 50, 60, 48), {p}
- ( 0, 0, 28, 38, 30, 6), {q}
- ( 0, 0, 44, 26, 24, 24), {r}
- ( 0, 14, 16, 12, 34, 28), {s}
- ( 0, 24, 62, 24, 26, 12), {t}
- ( 0, 0, 50, 50, 50, 30), {u}
- ( 0, 0, 50, 50, 50, 28), {v}
- ( 0, 0, 34, 42, 42, 28), {w}
- ( 0, 0, 54, 24, 12, 54), {x}
- ( 0, 0, 50, 62, 2, 28), {y}
- ( 0, 0, 60, 12, 48, 62), {z}
- ( 0, 14, 24, 48, 24, 14),(*{*)
- ( 0, 4, 4, 0, 4, 4), {|}
- ( 0, 56, 12, 6, 12, 56),(*}*)
- ( 0, 26, 36, 0, 0, 0), {~}
- ( 0, 8, 20, 34, 62, 0), {#127}
- ( 28, 50, 32, 50, 28, 48), {#128}
- ( 0, 50, 0, 50, 50, 30), {#129}
- ( 6, 8, 28, 62, 32, 28), {#130}
- ( 4, 10, 0, 30, 49, 31), {#131}
- ( 26, 0, 28, 50, 50, 30), {#132}
- ( 12, 2, 28, 34, 34, 30), {#133}
- ( 4, 10, 4, 28, 50, 30), {#134}
- ( 0, 30, 48, 30, 4, 24), {#135}
- ( 28, 0, 28, 62, 48, 28), {#136}
- ( 20, 0, 28, 62, 32, 28), {#137}
- ( 12, 2, 28, 62, 48, 28), {#138}
- ( 26, 0, 12, 12, 12, 12), {#139}
- ( 12, 18, 0, 12, 12, 12), {#140}
- ( 24, 4, 0, 12, 12, 12), {#141}
- ( 50, 0, 28, 50, 62, 50), {#142}
- ( 12, 0, 28, 50, 62, 50), {#143}
- ( 28, 62, 48, 60, 48, 62), {#144}
- ( 0, 52, 10, 28, 40, 22), {#145}
- ( 0, 14, 20, 62, 36, 38), {#146}
- ( 8, 20, 0, 28, 50, 28), {#147}
- ( 20, 0, 28, 50, 50, 28), {#148}
- ( 24, 4, 0, 28, 50, 28), {#149}
- ( 8, 20, 0, 50, 50, 30), {#150}
- ( 24, 4, 0, 50, 50, 30), {#151}
- ( 20, 0, 50, 62, 2, 28), {#152}
- ( 20, 0, 28, 50, 50, 28), {#153}
- ( 50, 0, 50, 50, 50, 62), {#154}
- ( 4, 30, 32, 32, 30, 4), {#155}
- ( 12, 18, 56, 16, 34, 62), {#156}
- ( 54, 8, 62, 8, 62, 8), {#157}
- ( 48, 40, 52, 46, 36, 38), {#158}
- ( 12, 10, 24, 12, 40, 24), {#159}
- ( 12, 16, 0, 28, 34, 30), {#160}
- ( 12, 16, 0, 8, 8, 8), {#161}
- ( 12, 16, 0, 28, 50, 28), {#162}
- ( 12, 16, 0, 50, 50, 30), {#163}
- ( 26, 36, 0, 44, 18, 18), {#164}
- ( 26, 36, 0, 50, 42, 38), {#165}
- ( 28, 36, 26, 0, 62, 0), {#166}
- ( 28, 34, 28, 0, 62, 0), {#167}
- ( 8, 0, 8, 16, 34, 28), {#168}
- ( 0, 0, 63, 48, 0, 0), {#169}
- ( 0, 0, 63, 3, 0, 0), {#170}
- ( 18, 20, 8, 16, 42, 10), {#171}
- ( 18, 20, 8, 20, 38, 2), {#172}
- ( 12, 0, 12, 12, 12, 0), {#173}
- ( 10, 20, 40, 20, 10, 0), {#174}
- ( 40, 20, 10, 20, 40, 0), {#175}
- ( 21, 42, 21, 42, 21, 42), {#176}
- ( 63, 63, 63, 63, 63, 63), {#177}
- ( 42, 21, 42, 21, 42, 21), {#178}
- ( 4, 4, 4, 4, 4, 4), {#179}
- ( 4, 4, 4, 60, 4, 4), {#180}
- ( 4, 4, 60, 4, 60, 4), {#181}
- ( 10, 10, 10, 58, 10, 10), {#182}
- ( 0, 0, 0, 62, 10, 10), {#183}
- ( 0, 0, 60, 4, 60, 4), {#184}
- ( 10, 10, 58, 2, 58, 10), {#185}
- ( 10, 10, 10, 10, 10, 10), {#186}
- ( 0, 0, 62, 2, 58, 10), {#187}
- ( 10, 10, 58, 2, 62, 0), {#188}
- ( 10, 10, 10, 62, 0, 0), {#189}
- ( 4, 4, 60, 4, 60, 0), {#190}
- ( 0, 0, 0, 60, 4, 4), {#191}
- ( 4, 4, 4, 7, 0, 0), {#192}
- ( 4, 4, 4, 63, 0, 0), {#193}
- ( 0, 0, 0, 63, 4, 4), {#194}
- ( 4, 4, 4, 7, 4, 4), {#195}
- ( 0, 0, 0, 63, 0, 0), {#196}
- ( 4, 4, 4, 63, 4, 4), {#197}
- ( 4, 4, 7, 4, 7, 4), {#198}
- ( 10, 10, 10, 11, 10, 10), {#199}
- ( 10, 10, 11, 8, 15, 0), {#200}
- ( 0, 0, 15, 8, 11, 10), {#201}
- ( 10, 10, 59, 0, 63, 0), {#202}
- ( 0, 0, 63, 0, 59, 10), {#203}
- ( 10, 10, 11, 8, 11, 10), {#204}
- ( 0, 0, 63, 0, 63, 0), {#205}
- ( 10, 10, 59, 0, 59, 10), {#206}
- ( 4, 4, 63, 0, 63, 0), {#207}
- ( 10, 10, 10, 63, 0, 0), {#208}
- ( 0, 0, 63, 0, 63, 4), {#209}
- ( 0, 0, 0, 63, 10, 10), {#210}
- ( 10, 10, 10, 15, 0, 0), {#211}
- ( 4, 4, 7, 4, 7, 0), {#212}
- ( 0, 0, 7, 4, 7, 4), {#213}
- ( 0, 0, 0, 15, 10, 10), {#214}
- ( 10, 10, 10, 63, 10, 10), {#215}
- ( 4, 4, 63, 4, 63, 4), {#216}
- ( 4, 4, 4, 60, 0, 0), {#217}
- ( 0, 0, 7, 4, 4, 4), {#218}
- ( 63, 63, 63, 63, 63, 63), {#219}
- ( 0, 0, 0, 63, 63, 63), {#220}
- ( 48, 48, 48, 48, 48, 48), {#221}
- ( 3, 3, 3, 3, 3, 3), {#222}
- ( 63, 63, 63, 0, 0, 0), {#223}
- ( 0, 0, 26, 36, 36, 26), {#224}
- ( 0, 28, 38, 44, 34, 44), {#225}
- ( 0, 62, 34, 32, 32, 32), {#226}
- ( 0, 0, 62, 20, 20, 20), {#227}
- ( 62, 18, 8, 16, 34, 62), {#228}
- ( 0, 0, 30, 36, 36, 24), {#229}
- ( 0, 18, 18, 30, 16, 48), {#230}
- ( 0, 0, 26, 44, 8, 8), {#231}
- ( 0, 62, 8, 20, 8, 62), {#232}
- ( 0, 28, 34, 62, 34, 28), {#233}
- ( 0, 28, 34, 34, 20, 54), {#234}
- ( 14, 16, 8, 28, 34, 28), {#235}
- ( 0, 0, 20, 42, 20, 0), {#236}
- ( 0, 2, 20, 42, 20, 32), {#237}
- ( 0, 30, 32, 62, 32, 30), {#238}
- ( 0, 0, 28, 34, 34, 34), {#239}
- ( 0, 62, 0, 62, 0, 62), {#240}
- ( 0, 8, 28, 8, 0, 62), {#241}
- ( 16, 8, 4, 8, 16, 62), {#242}
- ( 4, 8, 16, 8, 4, 62), {#243}
- ( 4, 10, 8, 8, 8, 8), {#244}
- ( 8, 8, 8, 8, 40, 16), {#245}
- ( 0, 8, 0, 62, 0, 8), {#246}
- ( 26, 36, 0, 26, 36, 0), {#247}
- ( 24, 36, 24, 0, 0, 0), {#248}
- ( 0, 0, 0, 12, 0, 0), {#249}
- ( 0, 0, 0, 4, 0, 0), {#250}
- ( 15, 8, 8, 40, 24, 8), {#251}
- ( 44, 18, 18, 0, 0, 0), {#252}
- ( 56, 4, 24, 32, 60, 0), {#253}
- ( 0, 0, 28, 28, 0, 0), {#254}
- ( 0, 0, 0, 0, 0, 0));{#255}
-
- VAR Steigung:BYTE; {entscheidet, welcher Alg. Anwendung findet}
- DY_mal2,DY_m_DX_mal2:INTEGER;
- oldMode:byte;
- regs:registers;
-
- IsAT:BYTE;
- TimeFlag:BYTE;
- CycleTime:LONGINT;
-
- SPRITEAD :ARRAY[0..LoadMAX] OF WORD; {normalisierte Segmentadressen}
- SPRITEPTR :ARRAY[0..LoadMAX] OF POINTER; {vollständige 32-Bit-Zeiger }
- SPRITESIZE:ARRAY[0..LoadMAX] OF WORD; {allozierte Spritegröße}
-
- CRTAddress, StatusReg : WORD;
-
- WinLowerRight,WinXMINdiv4,WinYMIN_mul_LINESIZE,
- WinYMINmLINESIZEaWinXMINdiv4:WORD;
- WinWidthDiv4:BYTE;
- BWinXMIN,BWinYMIN,BWinXMAX,BWinYMAX,BWinLowerRight,
- BWinYMIN_mul_LINESIZE:WORD; {Backups von Win* Variablen}
-
- SplitIndex,SplitIndex_mal2:INTEGER; {Splitpunkt für Sprites & Clipping}
-
-
- {-----------------------------------------------------}
-
- PROCEDURE ShadowTab; ASSEMBLER;
- {Pseudoprozedur, um Daten der Farbumsetztabelle im Codesegment }
- {unterzubringen, AUF KEINEN FALL AUFRUFEN!!! }
- {Defaultwerte entsprechen Abdunkelung auf 70% des Farb-Helligkeitswerts}
- ASM
- DB 254,104,120,124,112,108,114, 24, 20,128,144, 3,136, 5,140, 7
- DB 254,254, 17, 17, 18, 19, 20, 20, 21, 8, 23, 24, 24, 25, 26, 7
- DB 1, 1,107,108, 5,108,109, 4, 4, 4, 6, 6,116,116,117, 2
- DB 2, 2,123,124, 3,124,125, 1,152,155,156,156, 5,156,156,157
- DB 160,163,164,164,164,164,164,165,168,171,172,172, 3,172,172,173
- DB 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
- DB 24, 24, 24, 24, 24, 24, 24, 24,176,177,178,179,180,181,182,183
- DB 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
- DB 200,201,203,204,204,204,205,207,208,209,211,212,212,212,213,215
- DB 216,217,219,220,220,220,221,223,246,227,228,228,228,228,228,229
- DB 234,235,236,236,236,236,236,237,242,243,244,244,244,244,244,245
- DB 254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
- DB 254,254,254,254,254,254,254,254, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17,254,254,254,254,254,254,254, 7
- END;
-
- PROCEDURE CS_TranslateTab; ASSEMBLER;
- {kleine Pseudoprozedur, um die Umsetztabelle für die Bitmaske auch im}
- {Codesegment zu haben}
- ASM
- DB 1,2,4,8
- END;
-
- PROCEDURE SetShadowTab(brightness:BYTE);
- { in: brightness = gewünschte Helligkeit der Farben im Schattenbereich, }
- { in Prozent zu der Helligkeit ihrer Originalfarben }
- {out: ShadowTab = (Näherungs-)Farbtabelle für gewünschte Abdunkelung }
- { Schatten = neue Helligkeit (Schatten ist globale Variable!) }
- {rem: Defaultwert in ShadowTab ist 70% Helligkeit der Ursprungsfarben! }
- { Diese Routine dauert ihre Zeit (ca. 4 sec auf 8MHz-AT!) }
-
- VAR neue_Tabelle:ColorTable;
- p1:POINTER;
-
- BEGIN
- IF (brightness<0) OR (brightness>100)
- THEN BEGIN
- Error:=Err_InvalidPercentage;
- exit
- END;
- p1:=@neue_Tabelle; {Trick, da der Assembler nicht mit dem SS-Segment klarkommt}
- ASM
- MOV CX,256 {äußerer Schleifenzähler}
- LES DI,p1 {ES:DI = ^neue_Tabelle[i] }
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
-
- @outerloop:
- LODSB {AL = tempColors[i].red}
- MUL brightness {wird über Stack adressiert!}
- MOV DL,100
- DIV DL {AL = tempColors[i].red * brightness DIV 100}
- MOV BL,AL {BL := AL = neuer Rotanteil}
-
- LODSB {dto., für grün}
- MUL brightness
- MOV DL,100
- DIV DL
- MOV BH,AL {...nach BH}
-
- LODSB {dto., für blau}
- MUL brightness
- MOV DL,100
- DIV DL
- MOV DH,AL {...nach DH}
-
- {BL / BH / DH = RGB-Anteile der Farbe, für die eine Näherung zu finden ist}
- PUSH CX
- PUSH SI
- PUSH DI
- PUSH BP
-
- MOV DI,65535 {bisher gefundenes minimales Fehlerquadrat}
- MOV CX,256 {alle 256 Default-Farben durchsehen}
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
- @searchloop:
- MOV AL,BL {Differenz im Rotanteil berechnen}
- SUB AL,[SI]
- JL @noNewMin {neue Farbe darf nicht heller sein!}
- MUL AL {Fehlerquadrat berechnen}
- MOV BP,AX
-
- MOV AL,BH {dto., für Grünanteil}
- SUB AL,[SI+1]
- JL @noNewMin
- MUL AL
- ADD BP,AX
- JC @noNewMin {mordsmäßige Abweichungen sofort ignorieren}
-
- MOV AL,DH {dto., für Blauanteil}
- SUB AL,[SI+2]
- JL @noNewMin
- MUL AL
- ADD AX,BP
- JC @noNewMin
-
- CMP AX,DI {bessere Approximation gefunden?}
- JAE @noNewMin {nein}
- MOV DI,AX {ja, Fehlerquadrat und Farbe merken}
- MOV DL,CL
- OR DI,DI {Fehlerquadrat = 0?}
- JZ @ColorDone {ja, bessere Näherung können wir nicht mehr finden!}
-
- @noNewMin:
- ADD SI,3
- LOOP @searchloop
-
- CMP DI,65535 {keine Farbe gefunden?}
- JNE @ColorDone {doch, fertig!}
- MOV CX,256 {nein, also nochmal suchen}
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
- @searchloop2:
- LODSB
- SUB AL,BL {Diff ≈±2^6 -> Quadrat ≈±2^12 -> 3 * Quadrat < MaxInt}
- IMUL AL {also kein Overflow möglich}
- MOV BP,AX
-
- LODSB {dto., für Grünanteil}
- SUB AL,BH
- IMUL AL
- ADD BP,AX
-
- LODSB {dto., für Blauanteil}
- SUB AL,DH
- IMUL AL
- ADD AX,BP
-
- CMP AX,DI {bessere Approximation gefunden?}
- JAE @noNewMin2 {nein}
- MOV DI,AX {ja, Fehlerquadrat und Farbe merken}
- MOV DL,CL
-
- @noNewMin2:
- LOOP @searchloop2
-
-
- @ColorDone: {100h - DL = gefundene optimale Farbe}
- POP BP
- POP DI {ES:DI = ^neue_Tabelle[i] }
- POP SI {DS:SI = ^ActualColors[i] }
- POP CX
-
- MOV AL,DL {in neue_Tabelle[i] eintragen}
- NEG AL {AL = 100h - DL = beste Näherung}
- STOSB
-
- DEC CX {Ersatz für "LOOP @outerloop"; nächste Farbe!}
- JCXZ @fertig
- JMP @outerloop
- @fertig:
-
- END; {of ASM}
- MOVE(neue_Tabelle,@ShadowTab^,256); {Farbtabelle übernehmen}
- Schatten:=brightness
- END;
-
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- { in: pal = Zeiger auf zu setzende Palette }
- { update = TRUE/FALSE für: ShadowTab neu/nicht neu berechnen}
- {out: ActualColors = aktuelle Farbpalette }
- {rem: Palette wurde übernommen und evtl. ShadowTab neuberechnet }
- BEGIN
- IF @pal<>@ActualColors
- THEN ActualColors:=pal; {Farbpalette in ActualColors übernehmen}
- ASM
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
-
- CLI
-
- mov dx,StatusReg
- @WaitNotVSyncLoop:
- in al,dx
- and al,8
- jnz @WaitNotVSyncLoop
- @WaitVSyncLoop:
- in al,dx
- and al,8
- jz @WaitVSyncLoop
-
- MOV DX,3C8h
- XOR AL,AL
- OUT DX,AL
- INC DX
-
- MOV CX,256/2
- @L1:
- LODSW
- OUT DX,AL
- MOV AL,AH
- OUT DX,AL
- LODSW
- OUT DX,AL
- MOV AL,AH
- OUT DX,AL
- LODSW
- OUT DX,AL
- MOV AL,AH
- OUT DX,AL
- LOOP @L1
-
- STI
- END; {of ASM}
- IF update THEN SetShadowTab(Schatten)
- END;
-
- PROCEDURE GetPalette(VAR pal:Palette); ASSEMBLER;
- { in: pal = Zeiger auf Palette-Speicher}
- {out: pal = momentan aktuelle Palette }
- ASM
- CLI
- XOR AL,AL
- MOV DX,3C7h
- OUT DX,AL
- LES DI,pal
- MOV CX,768
- MOV DX,3C9h
- @L1:
- IN AL,DX
- STOSB
- LOOP @L1
- STI
- END;
-
- PROCEDURE FadeToPalette(destPal:Palette; AnzSteps:WORD);
- { in: ActualColors = aktuell gesetzte Farbpalette}
- { destPal = Zielpalette}
- { AnzSteps = Zwischenschrittanzahl}
- {out: ActualColors = destPal}
- {rem: Die Prozedur blendet von ActualColors zu destPal über, und zwar}
- { in AnzSteps Schritten}
- { Das Palettesetzen wird auf den vertikalen Retrace synchronisiert,}
- { so daß ein Zwischenschritt mindestens 1/70 sec benötigt}
- VAR oldColors,pal:Palette;
- i,steps:INTEGER;
- s,d:POINTER;
- BEGIN
- dec(anzsteps);
- IF anzsteps<1
- THEN steps:=1
- ELSE steps:=anzsteps; {steps ins selbe Segment wie pal bringen}
- oldColors:=ActualColors;
- pal:=destpal; {pal und oldColors ins selbe Segment bringen}
- s:=@pal; d:=@ActualColors;
- FOR i:=0 TO steps-1 DO
- BEGIN
- {jetzt per Assembler folgende Sequenz berechnen:}
- { FOR c:=0 TO 255 DO }
- { BEGIN }
- { ActualColors[c].red:=LONGINT(pal[c].red-oldColors[c].red)*i }
- { DIV steps+ oldColors[c].red; }
- { ActualColors[c].green:=LONGINT(pal[c].green-oldColors[c].green)*i }
- { DIV steps+ oldColors[c].green; }
- { ActualColors[c].blue:=LONGINT(pal[c].blue-oldColors[c].blue)*i }
- { DIV steps+ oldColors[c].blue; }
- { END; }
-
- ASM
- LES DI,d {ES:DI = Zeiger auf ActualColors-Tabelle}
- LDS SI,s {DS:SI = Zeiger auf pal-Tabelle}
- MOV BX,OFFSET oldColors-OFFSET pal -1 {DS:SI+BX+1 = Zeiger auf oldColors}
-
- MOV CX,256
- @docolor:
- XOR AH,AH
- LODSB {AX := pal[c].red}
- SUB AL,[SI+BX]
- SBB AH,0 {AX := pal[c].red - oldColors[c].red = delta}
- IMUL i {DX:AX := delta * i}
- IDIV steps {AX := delta * i/steps}
- ADD AL,[SI+BX] {AX := delta * i/steps + oldColors[c].red}
- STOSB
-
- {dto. für grün}
- XOR AH,AH
- LODSB
- SUB AL,[SI+BX]
- SBB AH,0
- IMUL i
- IDIV steps
- ADD AL,[SI+BX]
- STOSB
-
- {dto. für blau}
- XOR AH,AH
- LODSB
- SUB AL,[SI+BX]
- SBB AH,0
- IMUL i
- IDIV steps
- ADD AL,[SI+BX]
- STOSB
-
- LOOP @docolor
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
- SetPalette(ActualColors,FALSE)
- END;
- SetPalette(pal,TRUE)
- END;
-
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- { in: name = Name des zu ladenden Palette-Files (Typ: "*.PAL" )}
- { number = Nummer, die die erste Farbe aus diesem File bekommen soll }
- { ActualColors = gerade aktuelle Farbpalette}
- {out: Anzahl der aus dem File gelesenen Farben (0 = Fehler trat auf) }
- { pal = aus dem File gelesene Farbpalette, evtl. ergänzt}
- {rem: Alle nicht überschriebenen Farben werden in "pal" auf die Werte der }
- { gerade aktuellen Farben "ActualColors" gesetzt; die Palette wurde }
- { nur geladen, nicht gesetzt!}
- LABEL quitloop;
- VAR len:LONGINT;
- f:FileOfByte;
- i,count:WORD;
- TempPal:Palette;
- flag:BOOLEAN;
- tempName:STRING;
- BEGIN
- count:=0; {Zahl der bisher eingelesenen Paletteneinträge}
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
- _assign(f,name);
- {$I-} _reset(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- if (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN {Datei existiert nicht oder nicht unter diesem Pfad}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- LoadPalette:=0; exit
- END;
- len:=_filesize(f); {Dateilänge ermitteln}
- if (len mod 3<>0) OR (len>3*256) OR (len<3)
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
- IF len+number*3>3*256
- THEN BEGIN
- Error:=Err_PaletteWontFit;
- goto quitloop;
- END;
-
- TempPal:=ActualColors; {temporäre Palette mit aktuellen Farben vorbesetzen}
- {$I-}
- _blockread(f,TempPal[number],len);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quitloop;
- END;
-
- flag:=FALSE;
- FOR i:=number TO Pred(number+(len DIV 3))
- DO flag:=flag OR (TempPal[i].red>63)
- OR (TempPal[i].green>63)
- OR (TempPal[i].blue>63);
- IF flag
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
-
- {Alles ging gut: Palette zurückgeben}
- pal:=TempPal;
- count:=len DIV 3;
-
- quitloop: ;
- _close(f);
- LoadPalette:=count
- END;
-
- {Nun folgen die Codestücke, die Verwendung finden, um ein Sprite auf den }
- {Schirm zu bringen; die Schnittstelle ist für alle gleich: }
- { in: CX = Anzahl Bytes, die von... }
- { DS:SI = (Zeiger auf Quelladresse) nach... }
- { ES:BX = (Zeiger auf Zieladresse) zu bringen sind; }
- { DI = Bitplane (0..3) (=X-Koordinate AND 3) }
- { Die Bitmaske für den richtigen Schreibe-Planezugriff wurde bereits }
- { gesetzt, eine evtl. nötige Leseplane dagegen nicht! }
- { Die Routinen können sicher sein, daß CX<>0 ist }
- {rem: Jede dieser Routinen MUSS EXAKT 16 Bytes lang und VOLL RELOKATIBEL }
- { sein, sowie die Register BP,DS,ES unverändert lassen!!!!!!!!!!!!! }
- { Außerdem müssen die einzelnen Routinen zur Unterscheidbarkeit in }
- { ihren ersten zwei Bytes paarweise verschieden sein! }
-
- PROCEDURE Modus0; ASSEMBLER;
- {Modus 0 betrachtet die Farbe 0 als durchsichtig für den Hintergrund}
- ASM
- INC CX
- STC {BX so verringern, daß es zusammen mit SI zugleich}
- SBB BX,SI {als Zielindex verwendet werden kann}
- @L1:
- LODSB {Spritebyte holen }
- OR AL,AL {ist es gleich 0? }
- LOOPZ @L1 {ja, nichts zu tun}
- JCXZ @L2 {alle Bytes durch?}
- MOV ES:[BX+SI],AL {nein, übertragen }
- JMP @L1 {short} {nächstes Byte }
- @L2:
- END;
-
- PROCEDURE Modus1; ASSEMBLER;
- {Modus 1 schreibt die Daten sofort ohne weitere Untersuchung auf den Schirm}
- ASM
- MOV DI,BX {DI setzen, damit Stringbefehle verwendet werden können}
- XOR AX,AX {AX := 0 setzen}
- SHR CX,1 {Anzahl zu übertragender Wörter}
- REP MOVSW {Daten auf einen Satz übertragen}
- ADC CX,AX {noch ein einzelnes Byte übrig? }
- REP MOVSB
- MOV AX,AX {4 Füllbytes; schneller als 4 NOPs}
- MOV AX,AX
- END;
-
- PROCEDURE Modus2Work; ASSEMBLER;
- {Fortsetzung von Modus2 - all das, was nicht mehr in 16 Bytes unterzubringen}
- {war, kommt hierher}
- ASM
- OUT DX,AX {Lesezugriff auf passende Plane ermöglichen}
-
- PUSH DS {DS zeigt noch auf Spritedaten, muß aber auf }
- {Hintergrund zeigen! }
- MOV AX,ES {DS:SI := ES:DI (Quellzeiger:=Zielzeiger) }
- MOV DS,AX
- MOV SI,DI
- MOV BX,OFFSET ShadowTab {Zeiger auf Farbumsetztabelle setzen }
-
- @L4:
- LODSB {Hintergrundfarbe holen... }
- SEGCS XLAT {...mit Farbtabelle umsetzen}
- STOSB {...und auf aktueller Seite darstellen}
- LOOP @L4
-
- POP DS
- END;
-
- PROCEDURE Modus2; ASSEMBLER;
- {Modus 2 ist für "Schatten" und ähnliches gedacht: hierbei werden die }
- {eigentlichen Spritedaten ignoriert und stattdessen die Hintergrunddaten}
- {gelesen, die sich an der Spriteposition befinden und deren Farbwerte }
- {gegen die der Farbtabelle "ShadowTab" ersetzt (um bspw. Schatten zu }
- {erzeugen, müßte diese Tabelle zu jeder Farbe eine dunklere enthalten) }
- ASM
- MOV AX,DI {Bitplane für Lesezugriff nach AX bringen}
- MOV DI,BX {für Stringbefehle die Zieladresse nach DI bringen}
- MOV AH,AL {Bitplane ins Highbyte bringen}
- MOV AL,4
- MOV DX,3CEh
- MOV SI,OFFSET Modus2Work {fieser Trick: "CALL Modus2Work" würde (da re- }
- CALL SI {lativ codiert) zu falscher Adresse verzweigen!}
- END;
-
- PROCEDURE Modus3Work; ASSEMBLER;
- {Fortsetzung von Modus3 - all das, was nicht mehr in 16 Bytes unterzubringen}
- {war, kommt hierher}
- ASM
- STC
- SBB BX,SI {Quell-/Zieldaten beide mit nur 1 Indexregister ansprechen}
- MOV DX,BP {BP-Register retten}
- MOV BP,BX
- MOV BX,OFFSET ShadowTab {Zeiger auf Farbumsetztabelle setzen }
-
- @L1:
- LODSB {Spritedatum holen... }
- OR AL,AL { (Farbe 0 ignorieren, da "durchsichtig") }
- LOOPZ @L1
- JCXZ @L2
- MOV AL,ES:[BP+SI] {Hintergrundfarbe holen... }
- SEGCS XLAT {...mit Farbtabelle umsetzen}
- MOV ES:[BP+SI],AL {...und auf aktueller Seite darstellen}
- JMP @L1
- @L2:
- MOV BP,DX {alten Inhalt von BP wiederherstellen}
- END;
-
- PROCEDURE Modus3; ASSEMBLER;
- {Modus 3 ist ebenfalls für "Schatten" gedacht: hierbei werden alle Sprite- }
- {punkte, deren Farbe <>0 ist berücksichtigt: die Hintergrundfarbe, die sich }
- {unter diesen Punkten befindet, wird gegen den korrespondierenden Farbwert }
- {aus der Tabelle "ShadowTab" ersetzt. }
- {In anderen Worten: dieser Modus entspricht dem Modus 2, mit dem Unterschied,}
- {daß die Spritefarbe 0 als für den Schatten durchsichtig betrachtet wird! }
- ASM
- MOV DX,3CEh {Zugriff auf Leseplane vorbereiten:}
- MOV AX,DI
- MOV AH,AL {Leseplane nach AH bringen}
- MOV AL,4
- OUT DX,AX {Lesezugriff auf passende Plane ermöglichen}
- INC CX {Anzahl Bytes um 1 erhöhen (wg. LODSB) }
- MOV AX,OFFSET Modus3Work {Trick damit Code relokatibel wird!}
- CALL AX
- END;
-
- PROCEDURE Adressen; ASSEMBLER;
- {Tabelle der Startadressen der 3 Routinen im Codesegment}
- ASM
- DW OFFSET Modus0
- DW OFFSET Modus1
- DW OFFSET Modus2
- DW OFFSET Modus3
- END;
-
-
- PROCEDURE GADR; ASSEMBLER;
- {Tabelle der Grafikzeilen-Startadressen (Offset-Anteil)}
- ASM
- DW $0000,$0050,$00A0,$00F0,$0140,$0190,$01E0,$0230
- DW $0280,$02D0,$0320,$0370,$03C0,$0410,$0460,$04B0
- DW $0500,$0550,$05A0,$05F0,$0640,$0690,$06E0,$0730
- DW $0780,$07D0,$0820,$0870,$08C0,$0910,$0960,$09B0
- DW $0A00,$0A50,$0AA0,$0AF0,$0B40,$0B90,$0BE0,$0C30
- DW $0C80,$0CD0,$0D20,$0D70,$0DC0,$0E10,$0E60,$0EB0
- DW $0F00,$0F50,$0FA0,$0FF0,$1040,$1090,$10E0,$1130
- DW $1180,$11D0,$1220,$1270,$12C0,$1310,$1360,$13B0
- DW $1400,$1450,$14A0,$14F0,$1540,$1590,$15E0,$1630
- DW $1680,$16D0,$1720,$1770,$17C0,$1810,$1860,$18B0
- DW $1900,$1950,$19A0,$19F0,$1A40,$1A90,$1AE0,$1B30
- DW $1B80,$1BD0,$1C20,$1C70,$1CC0,$1D10,$1D60,$1DB0
- DW $1E00,$1E50,$1EA0,$1EF0,$1F40,$1F90,$1FE0,$2030
- DW $2080,$20D0,$2120,$2170,$21C0,$2210,$2260,$22B0
- DW $2300,$2350,$23A0,$23F0,$2440,$2490,$24E0,$2530
- DW $2580,$25D0,$2620,$2670,$26C0,$2710,$2760,$27B0
- DW $2800,$2850,$28A0,$28F0,$2940,$2990,$29E0,$2A30
- DW $2A80,$2AD0,$2B20,$2B70,$2BC0,$2C10,$2C60,$2CB0
- DW $2D00,$2D50,$2DA0,$2DF0,$2E40,$2E90,$2EE0,$2F30
- DW $2F80,$2FD0,$3020,$3070,$30C0,$3110,$3160,$31B0
- DW $3200,$3250,$32A0,$32F0,$3340,$3390,$33E0,$3430
- DW $3480,$34D0,$3520,$3570,$35C0,$3610,$3660,$36B0
- DW $3700,$3750,$37A0,$37F0,$3840,$3890,$38E0,$3930
- DW $3980,$39D0,$3A20,$3A70,$3AC0,$3B10,$3B60,$3BB0
- DW $3C00,$3C50,$3CA0,$3CF0,$3D40,$3D90,$3DE0,$3E30
- DW $3E80
- END;
-
- FUNCTION EMSinstalled(VAR PageFrameSeg:WORD):Boolean;
- { in: - }
- {out: PageFrameSeg = Segmentadresse des EMS-Puffers}
- { TRUE/FALSE für: EMS installiert/nicht installiert}
- { Error, EMSError = evtl. Fehlercode}
- {rem: Für USEEMS=FALSE wird immer FALSE zurückgegeben }
- TYPE Tag=ARRAY[1..8] OF CHAR;
- VAR p:POINTER;
- Begin
- EMSError:=0;
- IF NOT USEEMS
- THEN BEGIN
- EMSinstalled:=FALSE;
- exit
- END;
- GetIntVec(EMSInt,p);
- IF Tag(Ptr(SEG(p^),$A)^)='EMMXXXX0'
- THEN BEGIN {EMS-Handler vorhanden, aber bitte mind. V3.2:}
- WITH Regs DO
- BEGIN
- AH:=$46; Intr(EMSInt,Regs); {Versionscode holen}
- EMSInstalled:=AL>=$32; {Version >= 3.2 ? }
-
- AH:=$41; Intr(EMSInt,Regs); {BX=Segmentadresse, AH=evtl. Fehler}
- PageFrameSeg:=BX;
- EmsError:=AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END
- ELSE EMSInstalled:=FALSE
- End;
-
- FUNCTION EMSPagesAvailable:WORD;
- { in: - }
- {out: liefert Anzahl verfügbarer EMS Seiten (a 16K zurück)}
- { Error, EMSError = evtl. Fehlercode}
- {rem: nur aufrufen, wenn EMSinstalled = TRUE!}
- BEGIN
- WITH Regs DO
- BEGIN
- AH:=$42; Intr(EMSInt,Regs); {bestimme Anzahl freie Seiten}
- EMSPagesAvailable:=BX;
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- FUNCTION EMSAllocate(pages:Word):WORD;
- { in: pages = #zu belegende EMS-Seiten}
- {out: Handle auf diesen EMS-Bereich}
- { Error, EMSError = evtl. Fehlercode}
- {rem: pages darf die PagesAvail-Anzahl nicht überschreiten!}
- BEGIN
- With Regs do
- BEGIN
- AH:=$43;
- BX:=pages;
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- EMSAllocate := DX;
- END;
- END;
-
- Procedure EMSSwapPageIn(EMSHandle, LogicNr,PhysicalNr:Word);
- { in: EMSHandle = Handle eines allozierten EMS-Blocks}
- { LogicNr = logische Seite innerhalb dieses EMS-Blockes}
- { PhysicalNr = physikalische Seite des EMS-Frames (=0..3) }
- {out: Error, EMSError = evtl. Fehlercode}
- {rem: Mapped die logische Seite "LogicNr" des EMS-Bereichs, der mit dem}
- { Handle "EMSHandle" alloziert wurde, in die physikalische Seite }
- { "PhysicalNr"}
- { Zugriff ist anschließend über MEM[BACKGNDADR:PhysicalNr*$4000] }
- { möglich}
- { PhysicalNr = 0..3}
- { LogicNr = 0..allozierte Pageanzahl-1}
- BEGIN
- With Regs do
- BEGIN
- AH:=$44; DX:=EMSHandle; BX:=LogicNr; AL:=PhysicalNr;
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- PROCEDURE EMSFillFrame(EMSHandle:WORD);
- { in: EMSHandle = Handle auf 4 Seiten großen EMS-Bereich}
- {out: EMS-Frame-Puffer wurde mit den ersten 4 Seiten gefüllt}
- { Error, EMSError = evtl. Fehlercode}
- CONST a:ARRAY[0..7] OF WORD=(0,0,1,1,2,2,3,3);
- BEGIN
- With Regs do
- BEGIN
- AX:=$5000; DX:=EMSHandle; CX:=4;
- DS:=Seg(a); SI:=Ofs(a);
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- PROCEDURE EMSRelease(handle:WORD);
- { in: handle = Handle des freizugebenden EMS-Blockes}
- {out: Error, EMSError = evtl. Fehlercode}
- {rem: EMS-Block wurde freigegeben}
- BEGIN
- With Regs do
- BEGIN
- AH:=$45;
- DX:=handle;
- Intr(EMSInt,Regs);
- EmsError:=AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- FUNCTION EMSIsHardwareEMS:BOOLEAN;
- { in: - }
- {out: FALSE, wenn EMS nur emuliert wird}
- { Error, EMSError = evtl. Fehlercode}
- {rem: Die Prüfung wird wie in der LIM4.0-Spezifikation empfohlen dadurch}
- { durchgeführt, daß eine logische Seite unter allen physikalischen }
- { Seiten eingeblendet wird}
- CONST a:ARRAY[0..7] OF WORD=(0,0,0,1,0,2,0,3);
- VAR SegAdr,handle:WORD;
- mirror:BOOLEAN;
- BEGIN
- IF NOT(EMSInstalled(SegAdr)) OR (EMSPagesAvailable<1)
- THEN EMSIsHardwareEMS:=TRUE {irgendne bessere Idee?}
- ELSE BEGIN
- handle:=EMSAllocate(1);
- With Regs do
- BEGIN {log. Seite 0 in alle 4 physikalischen Seiten einblenden}
- AX:=$5000; DX:=handle; CX:=4;
- DS:=Seg(a); SI:=Ofs(a);
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- MEM[SegAdr:16383]:=0;
- mirror:=(MEM[SegAdr:1*16384+16383] OR
- MEM[SegAdr:2*16384+16383] OR
- MEM[SegAdr:3*16384+16383])=0;
- MEM[SegAdr:16383]:=$FF;
- mirror:=mirror AND
- ((MEM[SegAdr:1*16384+16383] AND
- MEM[SegAdr:2*16384+16383] AND
- MEM[SegAdr:3*16384+16383])=$FF);
- EMSRelease(handle);
- EMSIsHardWareEMS:=mirror
- END;
- END;
-
- PROCEDURE EnsureEMSConsistency(EMSHandle:WORD);
- { in: EMSused = TRUE}
- { EMSHandle = Handle für allozierten EMS-Block}
- { BACKGNDADR:0 = Start des EMS-Frames}
- {out: Der EMS-Frame enthält die gewünschten 64K Daten}
- BEGIN
- EMSFillFrame(EMSHandle); {Zugriff auf EMS vorbereiten}
- END;
-
- FUNCTION AT:BOOLEAN;
- { in: - }
- {out: TRUE/FALSE, wenn die Maschine (mindestens) ein AT ist}
- BEGIN
- AT:=MEM[$F000:$FFFE]=$FC
- END;
-
-
- PROCEDURE SetCycleTime(milliseconds:WORD);
- { in: Mindestzeit eines Animationszyklus in Millisekunden}
- {out: CycleTime := dieser Wert in Mikrosekunden}
- { TimeFlag := $80}
- {rem: Für den ersten Animationszyklus nach Aufruf dieser Routine }
- { gilt wg. TimeFlag := $80 die Zeitbedingung noch nicht! }
- { Schaltet der Benutzer (durch Angabe von milliseconds=0) die}
- { Zeitüberwachung explizit ab, so wird das durch IsAT := $80,}
- { d.h.: "Rechner ist ein PC" vorgetäuscht. Sonst ist IsAT = 0}
- BEGIN
- TimeFlag:=$80;
- CycleTime:=LONGINT(milliseconds)*LONGINT(1000);
- IF (milliseconds<>0) AND AT
- THEN IsAT:=0 {ja, Zeitüberwachung soll benutzt werden }
- ELSE IsAT:=$80 {nein, keine möglich oder nicht gewünscht }
- END;
-
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- { in: nr = Spriteladenummer des ersten Sprites des Zyklus }
- { len = Länge des zu definierenden Spritezyklus }
- {out: NextSprite[nr] bis NextSprite[nr+len-1] wurden so gesetzt,}
- { daß sie im Ring aufeinander zeigen, d.h.: sie bilden }
- { einen Spritezyklus}
- {rem: Soll der Zyklus aus nicht direkt aufeinanderfolgenden }
- { (physikalischen) Sprites gebildet werden, so müssen die }
- { entsprechenden Einträge in NextSprite[] manuell gemacht }
- { werden }
- { Diese Routine verwendet SpriteLADEnummern!}
- VAR i:WORD;
- BEGIN
- IF (nr<1) OR (nr+len-1>LoadMAX)
- THEN Error:=Err_InvalidSpriteLoadNumber
- ELSE BEGIN
- FOR i:=nr TO nr+len-2 DO NextSprite[i]:=SUCC(i);
- NextSprite[PRED(nr+len)]:=nr {letztes Sprite zeigt auf erstes}
- END;
- END;
-
-
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:WORD):POINTER;
- { in: (x1,y1) = linke obere Ecke des zu sichernden Bildausschnittes }
- { (x2,y2) = rechte untere Ecke dazu (alles virtuelle Koordinaten!) }
- { pa = Grafikseite, von der der Ausschnitt zu sichern ist (0..3) }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- {out: Zeiger auf Heapbereich, der den kopierten Bildausschnitt enthält }
- { left_cut= evtl. nötiger linker Cutoff des Bildausschnittes (gibt an,}
- { um wieviel Punkte der Ausschnitt links außerhalb des }
- { Bildschirm ragte) }
- { right_cut, top_cut, bottom_cut = dto., für andere Ränder }
- { was_cut = TRUE/FALSE, falls ein zurechtstutzen des Bildausschnittes }
- { nötig war/nicht nötig war }
- {rem: Der benötigte Speicher wird von der Routine automatisch reserviert }
- { Sollte dies nicht möglich sein (oder liegt der Bildausschnitt gänz- }
- { lich außerhalb des sichtbaren Bereichs), so wird NIL zurückgegeben! }
- { Nur wenn "was_cut" TRUE ist, sind die Werte der globalen "..._cut" }
- { Variablen <>0 gesetzt worden, d.h.: ist der Ausschnitt _ganz_ außer-}
- { halb des Bildes (also zurückgegebener Zeiger=NIL), dann liefert die }
- { Routine trotzdem "was_cut"=FALSE!}
- VAR len,breite,hoehe,StartAdr,actualAdr,SegmAdr:WORD;
- p:POINTER;
- BEGIN
- was_cut:=FALSE; left_cut:=0; right_cut:=0; top_cut:=0; bottom_cut:=0;
- dec(x1,StartVirtualX); {Bildschirmkoordinaten berechnen}
- dec(y1,StartVirtualY);
- IF (x1>XMAX) or (y1>YMAX) or (x2<0) or (y2<0) or (x1>x2) or (y1>y2)
- THEN BEGIN {Bildausschnitt nicht auf dem Bildschirm}
- GetImage:=NIL;
- exit
- END;
- {Ausschnitt auf Bildschirm zurechtklippen:}
- IF x1<0 THEN BEGIN left_cut :=-x1; x1:=0; was_cut:=TRUE END;
- IF y1<0 THEN BEGIN top_cut:=-y1; y1:=0; was_cut:=TRUE END;
- IF x2>XMAX THEN BEGIN right_cut :=x2-XMAX; x2:=XMAX; was_cut:=TRUE END;
- IF y2>YMAX THEN BEGIN bottom_cut:=y2-YMAX; y2:=YMAX; was_cut:=TRUE END;
-
- breite:=SUCC(x2-x1); hoehe:=SUCC(y2-y1);
- len:=breite*hoehe+2*2; {1 Pixel = 1 Byte; dazu: 2 Wörter für breite & hoehe}
- IF len>MaxAvail
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- GetImage:=NIL;
- exit
- END;
- IF (pa<0) OR (pa>SCROLLPAGE) {Seitennummer muß 0..3 sein}
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- GetImage:=NIL;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- GetMem(p,len); {Speicher auf dem Heap besorgen}
- IF pa<>BACKGNDPAGE
- THEN ASM {VRAM nach RAM}
- CLD
- LES DI,p {ES:DI = Zeiger auf den besorgten Speicher}
- MOV AX,breite
- STOSW {Breite zuerst ablegen...}
- MOV AX,hoehe
- STOSW {...gefolgt von der Höhe, danach dann die Daten}
-
- MOV BX,AX {BX := hoehe (für später) }
- MOV SI,y1
- SHL SI,1
- MOV SI,CS:[OFFSET gadr + SI] {SI := y1 * LINESIZE}
- MOV AX,x1
- MOV DL,AL
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI := Offsetanteil der Startadresse}
- MOV StartAdr,SI
- MOV actualAdr,SI
- AND DL,3
- MOV AH,DL
- MOV AL,4
- MOV DX,3CEh
- OUT DX,AX {Startplane anwählen}
- MOV DS,SegmAdr
-
- {DS:SI = Zeiger auf erstes zu speicherndes Byte; ES:DI = Zieladr. dafür}
- {AH = Startplane, AL = 4, BX = abzuarbeitende Zeilenanzahl}
-
- MOV DX,breite
- ADD DX,3
- SHR DX,1
- SHR DX,1 {DX = Anzahl zu sichernde Bytes je Zeile}
-
- @L1:
- MOV CX,DX {Daten einer Zeile abspeichern}
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr {Quellzeiger um 1 Grafikzeile weitersetzen}
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX {Zeilenzähler verringern}
- JNE @L1
-
- INC AH {nächste Plane anwählen}
- CMP AH,4
- JNE @nowrap1 {wrap in den Bitplanes bedeutet: Startadresse}
- MOV AH,0 {um 1 Adresse weitersetzen! }
- INC StartAdr
- @nowrap1:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L2:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L2
-
- INC AH
- CMP AH,4
- JNE @nowrap2
- MOV AH,0
- INC StartAdr
- @nowrap2:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L3:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L3
-
- INC AH
- CMP AH,4
- JNE @nowrap3
- MOV AH,0
- INC StartAdr
- @nowrap3:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L4:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- ELSE BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- ASM {RAM nach RAM}
- CLD
- LES DI,p {ES:DI = Zeiger auf den besorgten Speicher}
- MOV AX,breite
- STOSW {Breite zuerst ablegen...}
- MOV AX,hoehe
- STOSW {...gefolgt von der Höhe, danach dann die Daten}
-
- MOV DX,AX {DX := hoehe (für später) }
- MOV SI,y1
- SHL SI,1
- MOV SI,CS:[OFFSET gadr + SI] {SI := y1 * LINESIZE}
- MOV AX,x1
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI := Offsetanteil der Startadresse}
- AND BX,3
- MOV AH,BL
- SHL BX,1
- ADD SI,[OFFSET BACKTab + BX] {Startplane anwählen}
- MOV StartAdr,SI
- MOV actualAdr,SI
- MOV DS,SegmAdr
- MOV BX,DX
-
- {DS:SI = Zeiger auf erstes zu speicherndes Byte; ES:DI = Zieladr. dafür}
- {AH = Startplane, BX = abzuarbeitende Zeilenanzahl}
-
- MOV DX,breite
- ADD DX,3
- SHR DX,1
- SHR DX,1 {DX = Anzahl zu sichernde Bytes je Zeile}
-
- @L1:
- MOV CX,DX {Daten einer Zeile abspeichern}
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr {Quellzeiger um 1 Grafikzeile weitersetzen}
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX {Zeilenzähler verringern}
- JNE @L1
-
- INC AH {nächste Plane anwählen}
- ADD StartAdr,PAGESIZE
- CMP AH,4
- JNE @nowrap1 {wrap in den Bitplanes bedeutet: Startadresse}
- MOV AH,0 {um 1 Adresse weitersetzen! }
- SUB StartAdr,4*PAGESIZE -1
- @nowrap1:
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L2:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L2
-
- INC AH
- ADD StartAdr,PAGESIZE
- CMP AH,4
- JNE @nowrap2
- MOV AH,0
- SUB StartAdr,4*PAGESIZE -1
- @nowrap2:
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L3:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L3
-
- INC AH
- ADD StartAdr,PAGESIZE
- CMP AH,4
- JNE @nowrap3
- MOV AH,0
- SUB StartAdr,4*PAGESIZE -1
- @nowrap3:
- MOV BX,hoehe
- MOV DX,breite
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L4:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
- END;
- GetImage:=p
- END;
-
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:WORD);
- { in: (x,y) = linke obere Ecke des Zieles (in virtuellen Koordinaten) }
- { p = Zeiger auf (durch GetImage erstellten) Bildausschnitt }
- { pa = Grafikseite, in die der Bildausschnitt kopiert werden soll}
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- {out: - }
- {rem: Der Bildausschnitt wurde zur Bildschirmdarstellung zurechtgeklippt}
- { Bei Übergabe von NIL als Zeiger stellt die Routine gar nichts dar }
- { Dies hilft für eine direkte Übernahme der von GetImage gelieferten}
- { Werte!}
- VAR breite,hoehe,SegmAdr,actualAdr,StartAdr,breite1,breite2,breite3,breite4,
- licut_div4,topcut,pl_adr1,pl_adr2,pl_adr3,pl_adr4:WORD;
- licutoff,temp:INTEGER;
- BEGIN
- IF p=NIL THEN exit;
- dec(x,StartVirtualX); {Bildschirmkoordinaten berechnen}
- dec(y,StartVirtualY);
- IF (x>XMAX) or (y>YMAX) THEN exit;
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- breite:=MEMW[SEG(p^):OFS(p^)];
- hoehe :=MEMW[SEG(p^):OFS(p^)+2];
- IF (x+breite<=0) or (y+hoehe<=0) THEN exit;
- IF x<0 THEN BEGIN licutoff:=-x; x:=0 END
- ELSE licutoff:=0;
- IF y<0 THEN BEGIN
- topcut:=-y;
- y:=0
- END
- ELSE topcut:=0;
-
- breite1:=(breite + 3) shr 2; {Breite einer Zeile für die erste, zweite,}
- breite2:=(breite + 2) shr 2; {dritte und vierte Bitplane}
- breite3:=(breite + 1) shr 2;
- breite4:=(breite + 0) shr 2;
-
- {Anfangsadressen der 4 Bitplanes berechnen; dabei evtl. linken cutoff mit}
- {einbeziehen (plus 4 Bytes zum überspringen von "breite" und "hoehe" }
- licut_div4:=licutoff shr 2;
- pl_adr1:=4 +licut_div4 +topcut*breite1;
- pl_adr2:=4 +licut_div4 +topcut*breite2 +hoehe*breite1;
- pl_adr3:=4 +licut_div4 +topcut*breite3 +hoehe*(breite1+breite2);
- pl_adr4:=4 +licut_div4 +topcut*breite4 +hoehe*(breite1+breite2+breite3);
-
- {licutoff mod 4 gibt an, in welcher Reihenfolge die Punkte aus dem Heap }
- {gelesen werden müssen: 0 = Planereihenfolge (1,2,3,4); 1=(2,3,4,1); }
- {2=(3,4,1,2); 3=(4,1,2,3); zu beachten ist, daß die Breiten der einzelnen}
- {Bitplanetabellen natürlich mit diesen verbunden bleibt und deshalb }
- {mitgetauscht werden muß!}
- ASM
- CLD
- MOV AX,licutoff
- AND AL,3
- OR AL,AL
- JE @no_exchange
- CMP AL,1
- JNE @L10
-
- MOV AX,pl_adr2 {Verschiebung um 1 Bit: }
- MOV BX,pl_adr3 {AX = Plane2, BX = Plane3, CX = Plane4, DX = Plane1}
- MOV CX,pl_adr4
- MOV DX,pl_adr1 {wrap-around, deshalb: Adresse um 1 erhöhen, was }
- INC DX {einer Weitersetzung um 4 Bildpunkte entspricht }
- MOV pl_adr1,AX {(z.B.: Pixel (1,5,9,...),(2,6,10,...),(3,7,11,...)}
- MOV pl_adr2,BX {und (0,4,8,...); letztere Bitplane wird um 1 Byte }
- MOV pl_adr3,CX {weitergesetzt: liefert (richtige) (4,8,12,...) }
- MOV pl_adr4,DX {(Planes abwechselnd von oben nach unten lesen!) }
- MOV AX,breite2 {Jetzt Planebreiten: }
- MOV BX,breite3 {AX = Plane2, BX = Plane3, CX = Plane4, DX = Plane1}
- MOV CX,breite4
- MOV DX,breite1
- JMP @store
-
- @L10:
- CMP AL,2
- JNE @L20
-
- MOV AX,pl_adr3 {Verschiebung um 2 Bit: }
- MOV BX,pl_adr4 {AX = Plane3, BX = Plane4, CX = Plane1, DX = Plane2}
- MOV CX,pl_adr1
- INC CX
- MOV DX,pl_adr2
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite3 {dto. für Planebreiten: }
- MOV BX,breite4 {AX = Plane3, BX = Plane4, CX = Plane1, DX = Plane2}
- MOV CX,breite1
- MOV DX,breite2
- JMP @store
- @L20:
- MOV AX,pl_adr4 {Verschiebung um 3 Bit: }
- MOV BX,pl_adr1 {AX = Plane4, BX = Plane1, CX = Plane2, DX = Plane3}
- INC BX
- MOV CX,pl_adr2
- INC CX
- MOV DX,pl_adr3
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite4 {dto. für Planebreiten: }
- MOV BX,breite1 {AX = Plane4, BX = Plane1, CX = Plane2, DX = Plane3}
- MOV CX,breite2
- MOV DX,breite3
- @store:
- MOV breite1,AX
- MOV breite2,BX
- MOV breite3,CX
- MOV breite4,DX
-
- @no_exchange: {jetzt gilt: (pl_adr?,breite?) enthalten die Source-}
- {Bitplanes/-breiten in der richtigen Reihenfolge }
-
- MOV AX,topcut
- SUB hoehe,AX {Höhe um evtl. oberen cutoff korrigieren}
- MOV AX,licutoff
- SUB breite,AX {dto. für Breite und linken cutoff}
-
- MOV AX,x {falls Ausschnitt über rechten Bildschirmrand}
- ADD AX,breite {ragen würde: rechten cutoff bestimmen }
- SUB AX,XMAX+1
- JLE @no_recutoff
- SUB breite,AX {AX Punkte rechts abschneiden}
- @no_recutoff:
-
- MOV AX,y {genau dasselbe für unteren Bildschirmrand}
- ADD AX,hoehe
- SUB AX,YMAX+1
- JLE @no_bocutoff
- SUB hoehe,AX {AX Zeilen unten abschneiden}
- @no_bocutoff:
- END;
-
- IF pa<>BACKGNDPAGE
- THEN ASM {RAM nach VRAM}
- LDS SI,p
- ADD pl_adr2,SI {Offsetanteil des Zeigers zu den Planeadr. addieren}
- ADD pl_adr3,SI
- ADD pl_adr4,SI
-
- ADD SI,pl_adr1 {breite, hoehe und Teile oberhalb des Bildschirms}
- MOV ES,SegmAdr
-
- MOV DI,y
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y * LINESIZE}
- MOV AX,x
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y * LINESIZE + (x DIV 4)}
- MOV StartAdr,DI
- MOV actualAdr,DI
-
- AND BX,3 {Startplane := x mod 3}
- MOV AH,CS:[OFFSET CS_TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {als Schreibplane anwählen}
-
- MOV DX,hoehe
- MOV DI,actualAdr
-
- {DS:SI = Zeiger auf Daten, ES:DI = Zieladresse dafür auf dem Schirm,}
- {AH = Bitmaske für Zugriff, AL = 2 }
- MOV BX,breite
- ADD BX,3
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L1:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite1
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L1
-
-
- SHL AH,1 {nächste Bitplane anwählen; bei einem wrap von}
- CMP AH,16 {Bitplane 3 zu Bitplane 0 muß dabei die Start-}
- JNE @nowrap1 {adresse um 1 Byte weitergesetzt werden }
- MOV AH,1
- INC StartAdr
- @nowrap1:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr2
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L2:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite2
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L2
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap2
- MOV AH,1
- INC StartAdr
- @nowrap2:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr3
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L3:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite3
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L3
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap3
- MOV AH,1
- INC StartAdr
- @nowrap3:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr4
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L4:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite4
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- ELSE BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- ASM {RAM nach RAM}
- MOV AX,DS
- MOV ES,AX {ES := altes Datensegment}
-
- LDS SI,p
- ADD pl_adr2,SI {Offsetanteil des Zeigers zu den Planeadr. addieren}
- ADD pl_adr3,SI
- ADD pl_adr4,SI
-
- ADD SI,pl_adr1 {breite, hoehe und Teile oberhalb des Bildschirms}
-
- MOV DI,y
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y * LINESIZE}
- MOV AX,x
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y * LINESIZE + (x DIV 4)}
-
- AND BX,3 {Startplane := x mod 3}
- MOV AL,BL {Kopie davon nach AL}
- SHL BX,1
- ADD DI,ES:[OFFSET BACKTab + BX] {als Schreibplane anwählen}
- MOV StartAdr,DI
- MOV actualAdr,DI
-
- MOV DX,hoehe
- MOV DI,actualAdr
- MOV ES,SegmAdr
-
- {DS:SI = Zeiger auf Daten, ES:DI = Zieladresse dafür auf dem Schirm,}
- {AL = Startplane}
- MOV BX,breite
- ADD BX,3
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L1:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite1
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L1
-
-
- INC AL {nächste Bitplane anwählen; bei einem wrap von}
- ADD StartAdr,PAGESIZE {Bitplane 3 zu Bitplane 0 muß dabei die Start-}
- AND AL,3 {adresse um 1 Byte weitergesetzt werden }
- JNE @nowrap1
- SUB StartAdr,4*PAGESIZE-1
- @nowrap1:
- MOV SI,pl_adr2
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L2:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite2
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L2
-
-
- INC AL {nächste Bitplane anwählen; bei einem wrap von}
- ADD StartAdr,PAGESIZE {Bitplane 3 zu Bitplane 0 muß dabei die Start-}
- AND AL,3 {adresse um 1 Byte weitergesetzt werden }
- JNE @nowrap2
- SUB StartAdr,4*PAGESIZE-1
- @nowrap2:
- MOV SI,pl_adr3
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L3:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite3
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L3
-
-
- INC AL {nächste Bitplane anwählen; bei einem wrap von}
- ADD StartAdr,PAGESIZE {Bitplane 3 zu Bitplane 0 muß dabei die Start-}
- AND AL,3 {adresse um 1 Byte weitergesetzt werden }
- JNE @nowrap3
- SUB StartAdr,4*PAGESIZE-1
- @nowrap3:
- MOV SI,pl_adr4
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L4:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite4
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- END;
- END;
-
- PROCEDURE FreeImageMem(p:POINTER);
- { in: p = Zeiger auf per GetImage() gespeichertes Bild}
- {out: - }
- {rem: Der für das Bild reservierte Heap-Speicher wurde freigegeben}
- BEGIN
- IF p<>NIL THEN FreeMem(p,MEMW[Seg(p^):Ofs(p^)]*MEMW[Seg(p^):Ofs(p^)+2] + 2*2)
- END;
-
- PROCEDURE Screen(pa:WORD);
- { in: pa = anzuzeigende Bildschirmseite (0..1) }
- {out: - }
- {rem: Es wurde auf die Darstellung der Grafikseite pa umgeschaltet }
- { Dabei wurde NICHT auf irgendwelche Retrace-Signale synchronisiert}
- { Sinnvoll sind nur die Seiten 0 oder 1, es findet aber keine }
- { Überprüfung statt!}
- BEGIN
- ASM
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-Startadress-Register}
- CLI {Darf keinenfalls unterbrochen werden!}
- OUT DX,AL
- INC DX
- {Realisiere "AX := Offset_Adr[pa]":}
- MOV BX,pa
- MOV SI,BX
- AND SI,3 {Pagewert * 2 (da Worteinträge!)}
- SHL SI,1 {dazu Startadresse des Feldes addieren}
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. Verschiebung korrigieren}
- LODSW {und Wert holen}
- OUT DX,AL {LB der neuen Startadresse setzen}
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {HB der neuen Startadresse setzen}
- OUT DX,AL
- STI
- END;
- END;
-
- PROCEDURE InitGraph;
- { in: PAGE = aktuelle Grafikseite}
- {out: - }
- {rem: Schaltet die VGA-Karte in den 320x200x256x4-Modus; ACHTUNG! }
- { Dieser Modus ist verschieden vom Modus $13 der VGA!!! }
- { Dabei wird auf die Darstellung der Seite 1-PAGE geschaltet }
- { Es werden die Defaultfarben des Modus $13 gesetzt! }
- BEGIN
- ASM
- MOV AX,0013h {Mit BIOS Grafikmodus $13 (=320x200x256) setzen }
- INT 10h
- MOV DX,03C4h {im Sequenzer das Speichermodusregister auswählen }
- MOV AL,04
- OUT DX,AL
- INC DX {Daten über das zugehörige Datenregister lesen }
- IN AL,DX
- AND AL,0F7h {Bit 3 := 0: 4 Planes nicht chainen}
- OR AL,04 {Bit 2 := 1: kein odd/even-Mechan. }
- OUT DX,AL {Neuen Wert wirksam machen}
- MOV DX,03C4h {S.o.: Sequenzerregister2 (=Map-Maske) wählen,... }
- MOV AL,02
- OUT DX,AL
- INC DX
- MOV AL,0Fh {...und Zugriff auf alle 4 Bitmaps erlauben }
- OUT DX,AL
- MOV AX,0A000h {Ab Segment A000h nun 8000h logische Wörter = }
- MOV ES,AX {4*8000h physikalische Wörter (wg. den 4 Bit- }
- SUB DI,DI {planes) auf 0 setzen }
- MOV AX,DI
- MOV CX,8000h
- CLD
- REP STOSW
-
- MOV DX,CRTAddress {im CRT-Controller das underline-location- }
- MOV AL,14h {Register auswählen, den Wert aus dem }
- OUT DX,AL {zugehörigen Datenregister auslesen: }
- INC DX
- IN AL,DX
- AND AL,0BFh {Bit 6:=0: keine Doppelwortadressierung von}
- OUT DX,AL {Daten im Bildschirmspeicher durchführen}
- DEC DX
- MOV AL,17h {Mode-control-Register auswählen }
- OUT DX,AL
- INC DX
- IN AL,DX
- OR AL,40h {Bit 6 := 1: Adressierung des Speichers=lineares Bitfeld}
- OUT DX,AL
- END;
- Screen(1-PAGE); {sichtbar ist immer die nichtaktuelle Grafikseite}
- SetPalette(DefaultColors,FALSE) {Standardpalette setzen, sicher ist sicher}
- END;
-
-
- VAR d,dp,dq,WindowY2:INTEGER;
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
- { Color = Farbe (0..255) }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke}
- { WinClip = TRUE, wenn Linie auf Win* Fenster geclippt werden soll }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = Fenster für evtl. Clipping}
- {out: - }
- {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2) }
- { in der Farbe COLOR gezeichnet; die Routine führt dabei selber die }
- { Umrechnung der angeg. Koordinaten in absolute Bildschirmkoordinaten }
- { sowie evtl. notwendige Clipping-Schritte aus. }
- { Die Linie wird NICHT automatisch in den Hintergrund übernommen, }
- { d.h.: sie ist nur für einen Animationszyklus sichtbar (soll sie }
- { permanent bleiben, so muß sie in den Hintergrund gezeichnet werden!)}
- { (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
- { zuführen, da die gezeichnete Linie sonst sofort wieder verschwindet) }
- CONST CodeLinks =$7; {%0111}
- CodeRechts=$B; {%1011}
- CodeOben =$D; {%1101}
- CodeUnten =$E; {%1110}
- BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
-
- {zuerst Linie auf sichtbaren Bereich zurechtklippen; dazu Sutherland-}
- {Cohen-Algorithmus verwenden: 4 Bit-Code für links|rechts|oben|unten}
- ASM
- CLD
- XOR BX,BX
- MOV SI,XMAX
- XOR DI,DI
- MOV AX,YMAX
- CMP WinClip,FALSE
- JE @Start
- MOV BX,WinXMIN
- MOV SI,WinXMAX
- MOV DI,WinYMIN
- MOV AX,WinYMAX
- @Start:
- MOV WindowY2,AX
- {BX|SI|DI|WindowY2 = WinXMIN|WinXMAX|WinYMIN|WinYMAX bzw. 0|XMAX|0|YMAX}
-
- MOV CL,$F {mit %1111 anfangen}
- MOV AX,x2
- SUB AX,StartVirtualX {x2 in absolute Koordinaten umrechnen}
- MOV x2,AX
- CMP AX,BX {x2 < WindowX1 ?}
- JL @GC1Punkt2 {ja, Flag für "Punkt links vom Fenster" belassen}
- AND CL,CodeLinks {nein, Flag rücksetzen}
- @GC1Punkt2:
- CMP AX,SI {x2 > WindowX2 ?}
- JG @GC2Punkt2 {ja, Flag für "Punkt rechts vom Fenster" belassen}
- AND CL,CodeRechts {nein, Flag rücksetzen}
- @GC2Punkt2:
- MOV AX,y2
- SUB AX,StartVirtualY {y2 in absolute Koordinaten umrechnen}
- MOV y2,AX
- CMP AX,DI {y2 < WindowY1 ?}
- JL @GC3Punkt2 {ja, Flag für "Punkt oberhalb des Fensters" bel.}
- AND CL,CodeOben {nein, Flag rücksetzen}
- @GC3Punkt2:
- CMP AX,WindowY2 {y2 > WindowY2 ?}
- JG @GC4Punkt2 {ja, Flag für "Punkt unterhalb des Fensters" bel.}
- AND CL,CodeUnten
- @GC4Punkt2: {CL enthält jetzt den Gebietscode für Punkt 2}
-
- MOV AX,x1
- SUB AX,StartVirtualX {x1 in absolute Koordinaten umrechnen}
- MOV x1,AX
- MOV AX,y1
- SUB AX,StartVirtualY {y1 in absolute Koordinaten umrechnen}
- MOV y1,AX
-
- @Punkt1:
- MOV CH,$F {mit %1111 anfangen}
- MOV AX,x1
- CMP AX,BX {x1 < WindowX1 ?}
- JL @GC1Punkt1 {ja, Flag für "Punkt links vom Fenster" belassen}
- AND CH,CodeLinks {nein, Flag rücksetzen}
- @GC1Punkt1:
- CMP AX,SI {x1 > WindowX2 ?}
- JG @GC2Punkt1 {ja, Flag für "Punkt rechts vom Fenster" belassen}
- AND CH,CodeRechts {nein, Flag rücksetzen}
- @GC2Punkt1:
- MOV AX,y1
- CMP AX,DI {y1 < WindowY1 ?}
- JL @GC3Punkt1 {ja, Flag für "Punkt oberhalb des Fensters" bel.}
- AND CH,CodeOben {nein, Flag rücksetzen}
- @GC3Punkt1:
- CMP AX,WindowY2 {y1 > WindowY2 ?}
- JG @GC4Punkt1 {ja, Flag für "Punkt unterhalb des Fensters" bel.}
- AND CH,CodeUnten
- @GC4Punkt1: {CH enthält jetzt den Gebietscode für Punkt 1}
-
- {CL enthält den Gebietscode für Punkt 2, CH den für Punkt 1}
-
- MOV AX,CX
- AND AL,AH {Code1 AND Code2 <> 0 ?}
- JNZ @LineReady {ja, Linie ganz außerhalb des Windows}
- MOV AX,CX
- OR AL,AH {Code1 OR Code2 = 0 ?}
- JZ @DrawLine {ja, Linie ganz innerhalb des Windows}
-
- {Nun eigentliches Clipping vornehmen: }
- MOV AX,CX
- OR AH,AH {Code1 =0 ?}
- JNZ @CL3 {nein, alles ok}
- MOV AX,x1 {ja, Punkte vertauschen!}
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
- XCHG CL,CH
- @CL3:
- MOV AX,x2
- SUB AX,x1
- MOV dp,AX {dp := x2 - x1}
- MOV AX,y2
- SUB AX,y1
- MOV dq,AX {dq := y2 - y1}
-
- MOV AL,CH {AL := Code1}
- TEST AL,NOT CodeLinks {Punkt1 links des Windows?}
- JZ @CL4 {nein}
- {ja, neue Koordinaten berechnen:}
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX1 - X1) }
- { und x1 := WindowX1}
- MOV AX,BX
- SUB AX,x1 {AX := WindowX1-x1}
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,BX
- JMP @Punkt1
-
- @CL4:
- TEST AL,NOT CodeRechts {Punkt1 rechts des Windows?}
- JZ @CL5 {nein}
- {ja, berechne:}
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX2 - X1), x1 := WindowX2}
- MOV AX,SI {SI = WindowX2}
- SUB AX,x1
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,SI
- JMP @Punkt1
-
- @CL5:
- TEST AL,NOT CodeOben {Punkt1 oberhalb des Windows?}
- JZ @CL6 {nein}
- {ja, berechne:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY1 - y1), y1 := WindowY1 }
- MOV AX,DI {DI = WindowY1}
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- MOV y1,DI
- JMP @Punkt1
-
- @CL6:
- TEST AL,NOT CodeUnten {Punkt unterhalb des Windows?}
- JZ @Punkt1 {nein}
- {ja, berechne:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY2 - y1), y1 := WindowY2 }
- MOV AX,WindowY2
- PUSH AX
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- POP AX
- MOV y1,AX
- JMP @Punkt1
-
- {Hier gilt: die beiden Punkte wurden auf den sichtbaren Bereich zurecht-}
- {gestutzt; sollte die Gerade keinen sichtbaren Teil besitzen, so wurde }
- {direkt zu @LineReady verzweigt! }
- @DrawLine:
- MOV DX,x1
- SUB DX,x2
- JGE @posdx
- NEG DX
- @posdx:
- MOV AX,y1
- SUB AX,y2
- JGE @posdy
- NEG AX
- @posdy:
- {AX = neues deltaY, DX = neues deltaX}
- XOR CX,CX
- CMP AX,DX
- JBE @noswap1
- XCHG AX,DX
- INC CX
- @noswap1:
- {AX = deltaY, DX = deltaX (für CX=0), AX = deltaX, DX = deltaY (für CX=1)}
- SHL AX,1
- MOV dp,AX
- SUB AX,DX
- MOV d,AX
- SUB AX,DX
- MOV dq,AX
-
- JCXZ @then
- JMP @else
-
- @then:
- MOV CX,x2
- MOV AX,x1
- MOV DX,y1
- MOV BX,y2
- CMP AX,CX
- JBE @noswap2
- XCHG AX,CX
- XCHG DX,BX
- @noswap2:
- {AX = neues X1, CX = neues X2, DX = neues Y1, BX = neues Y2}
- SUB CX,AX
- INC CX {CX := x2 - x1 + 1 }
- MOV SI,LINESIZE
- CMP DX,BX
- JBE @okay1
- NEG SI
- @okay1:
- {SI = ±LINESIZE, CX = #Pixel, AX = X1, DX = Y1}
- MOV DI,DX
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y1 * LINESIZE}
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y1 * LINESIZE + (x1 DIV 4) }
-
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, da Worteinträge}
- ADD DI,[OFFSET BACKTab + BX] {Maske für Zugriff holen: BX * 16000}
-
- MOV BL,BACKGNDPAGE {BH = 0 -> BX = Zeichenseite}
- SHL BX,1
- MOV ES,[BX + OFFSET Segment_Adr -StartIndex*2] {ES:DI=Zeiger auf 1.Punkt}
-
- MOV AL,Color
- MOV DX,d
- MOV BX,dq
-
- @loop1:
- MOV ES:[DI],AL
- ADD DI,PAGESIZE
- JC @wrap1
- CMP DI,4*PAGESIZE
- JB @nowrap1
- @wrap1:
- SUB DI,4*PAGESIZE-1 {wieder in Plane0, aber 1 Byte weiter}
- @nowrap1: {AL = Farbe, SI = ±LINESIZE, ES:DI=Zeiger auf 1.Punkt}
- {BX = dq, DX = d}
- OR DX,DX
- JGE @newline
- ADD DX,dp
- LOOP @loop1
- JMP @raus
-
- @newline:
- ADD DI,SI
- ADD DX,BX
- LOOP @loop1
- JMP @raus
-
-
- @else:
- MOV CX,y2
- MOV AX,y1
- MOV DX,x1
- MOV BX,x2
- CMP AX,CX
- JBE @noswap3
- XCHG AX,CX
- XCHG DX,BX
- @noswap3:
- {AX = neues Y1, BX = neues X2, CX = neues Y2, DX = neues X1}
- SUB CX,AX
- INC CX
- MOV SI,PAGESIZE
- CMP DX,BX
- JBE @okay2
- NEG SI
- @okay2:
- {SI = ±PAGESIZE, CX = #Pixel, DX = X1, AX = Y1}
- MOV DI,AX
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y1 * LINESIZE}
- MOV BL,DL
- SHR DX,1
- SHR DX,1
- ADD DI,DX {DI := y1 * LINESIZE + (x1 DIV 4) }
-
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, da Worteinträge}
- ADD DI,[OFFSET BACKTab + BX] {Maske für Zugriff holen: BX * 16000}
-
- MOV BL,BACKGNDPAGE {BH = 0 -> BX = Zeichenseite}
- SHL BX,1
- MOV ES,[BX + OFFSET Segment_Adr -StartIndex*2] {ES:DI=Zeiger auf 1.Punkt}
-
- MOV AL,Color
- MOV DX,d
- MOV BX,dq
-
- @loop2:
- MOV ES:[DI],AL
- ADD DI,LINESIZE
- OR DX,DX
- JGE @newcolumn
- ADD DX,dp
- LOOP @loop2
- JMP @raus
-
- @newcolumn:
- OR SI,SI
- JGE @plus
- {Inkrement SI<0, auf underflow prüfen:}
- ADD DI,SI
- JC @nowrap2
- ADD DI,4*PAGESIZE-1
- JMP @nowrap2
- @plus:
- {Inkrement SI>0, auf overflow & >= 4*PAGESIZE prüfen}
- ADD DI,SI
- JC @wrap2
- CMP DI,4*PAGESIZE
- JB @nowrap2
- @wrap2:
- SUB DI,4*PAGESIZE-1
- @nowrap2:
- ADD DX,BX
- LOOP @loop2
- JMP @raus
-
- @raus:
- @LineReady:
- END;
- END;
-
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:WORD);
- { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
- { Color = Farbe (0..255) }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- { pa = Grafikseite, auf der gezeichnet werden soll (0..3) }
- { WinClip = TRUE, wenn Linie auf Win* Fenster geclippt werden soll }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = Fenster für evtl. Clipping}
- {out: - }
- {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2) }
- { in der Farbe COLOR gezeichnet; die Routine führt dabei selber die }
- { Umrechnung der angeg. Koordinaten in absolute Bildschirmkoordinaten }
- { sowie evtl. notwendige Clipping-Schritte aus. }
- { Die Linie wird NICHT automatisch in den Hintergrund übernommen, }
- { d.h.: sie ist nur für einen Animationszyklus sichtbar (soll sie }
- { permanent bleiben, so muß sie in den Hintergrund gezeichnet werden!)}
- { (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
- { zuführen, da die gezeichnete Linie sonst sofort wieder verschwindet) }
- CONST CodeLinks =$7; {%0111}
- CodeRechts=$B; {%1011}
- CodeOben =$D; {%1101}
- CodeUnten =$E; {%1110}
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE IF pa=BACKGNDPAGE
- THEN BackgroundLine(x1,y1,x2,y2)
- ELSE
- {zuerst Linie auf sichtbaren Bereich zurechtklippen; dazu Sutherland-}
- {Cohen-Algorithmus verwenden: 4 Bit-Code für links|rechts|oben|unten}
- ASM
- CLD
- XOR BX,BX
- MOV SI,XMAX
- XOR DI,DI
- MOV AX,YMAX
- CMP WinClip,FALSE
- JE @Start
- MOV BX,WinXMIN
- MOV SI,WinXMAX
- MOV DI,WinYMIN
- MOV AX,WinYMAX
- @Start:
- MOV WindowY2,AX
- {BX|SI|DI|WindowY2 = WinXMIN|WinXMAX|WinYMIN|WinYMAX bzw. 0|XMAX|0|YMAX}
-
- MOV CL,$F {mit %1111 anfangen}
- MOV AX,x2
- SUB AX,StartVirtualX {x2 in absolute Koordinaten umrechnen}
- MOV x2,AX
- CMP AX,BX {x2 < WindowX1 ?}
- JL @GC1Punkt2 {ja, Flag für "Punkt links vom Fenster" belassen}
- AND CL,CodeLinks {nein, Flag rücksetzen}
- @GC1Punkt2:
- CMP AX,SI {x2 > WindowX2 ?}
- JG @GC2Punkt2 {ja, Flag für "Punkt rechts vom Fenster" belassen}
- AND CL,CodeRechts {nein, Flag rücksetzen}
- @GC2Punkt2:
- MOV AX,y2
- SUB AX,StartVirtualY {y2 in absolute Koordinaten umrechnen}
- MOV y2,AX
- CMP AX,DI {y2 < WindowY1 ?}
- JL @GC3Punkt2 {ja, Flag für "Punkt oberhalb des Fensters" bel.}
- AND CL,CodeOben {nein, Flag rücksetzen}
- @GC3Punkt2:
- CMP AX,WindowY2 {y2 > WindowY2 ?}
- JG @GC4Punkt2 {ja, Flag für "Punkt unterhalb des Fensters" bel.}
- AND CL,CodeUnten
- @GC4Punkt2: {CL enthält jetzt den Gebietscode für Punkt 2}
-
- MOV AX,x1
- SUB AX,StartVirtualX {x1 in absolute Koordinaten umrechnen}
- MOV x1,AX
- MOV AX,y1
- SUB AX,StartVirtualY {y1 in absolute Koordinaten umrechnen}
- MOV y1,AX
-
- @Punkt1:
- MOV CH,$F {mit %1111 anfangen}
- MOV AX,x1
- CMP AX,BX {x1 < WindowX1 ?}
- JL @GC1Punkt1 {ja, Flag für "Punkt links vom Fenster" belassen}
- AND CH,CodeLinks {nein, Flag rücksetzen}
- @GC1Punkt1:
- CMP AX,SI {x1 > WindowX2 ?}
- JG @GC2Punkt1 {ja, Flag für "Punkt rechts vom Fenster" belassen}
- AND CH,CodeRechts {nein, Flag rücksetzen}
- @GC2Punkt1:
- MOV AX,y1
- CMP AX,DI {y1 < WindowY1 ?}
- JL @GC3Punkt1 {ja, Flag für "Punkt oberhalb des Fensters" bel.}
- AND CH,CodeOben {nein, Flag rücksetzen}
- @GC3Punkt1:
- CMP AX,WindowY2 {y1 > WindowY2 ?}
- JG @GC4Punkt1 {ja, Flag für "Punkt unterhalb des Fensters" bel.}
- AND CH,CodeUnten
- @GC4Punkt1: {CH enthält jetzt den Gebietscode für Punkt 1}
-
- {CL enthält den Gebietscode für Punkt 2, CH den für Punkt 1}
-
- MOV AX,CX
- AND AL,AH {Code1 AND Code2 <> 0 ?}
- JNZ @LineReady {ja, Linie ganz außerhalb des Windows}
- MOV AX,CX
- OR AL,AH {Code1 OR Code2 = 0 ?}
- JZ @DrawLine {ja, Linie ganz innerhalb des Windows}
-
- {Nun eigentliches Clipping vornehmen: }
- MOV AX,CX
- OR AH,AH {Code1 =0 ?}
- JNZ @CL3 {nein, alles ok}
- MOV AX,x1 {ja, Punkte vertauschen!}
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
- XCHG CL,CH
- @CL3:
- MOV AX,x2
- SUB AX,x1
- MOV dp,AX {dp := x2 - x1}
- MOV AX,y2
- SUB AX,y1
- MOV dq,AX {dq := y2 - y1}
-
- MOV AL,CH {AL := Code1}
- TEST AL,NOT CodeLinks {Punkt1 links des Windows?}
- JZ @CL4 {nein}
- {ja, neue Koordinaten berechnen:}
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX1 - X1) }
- { und x1 := WindowX1}
- MOV AX,BX
- SUB AX,x1 {AX := WindowX1-x1}
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,BX
- JMP @Punkt1
-
- @CL4:
- TEST AL,NOT CodeRechts {Punkt1 rechts des Windows?}
- JZ @CL5 {nein}
- {ja, berechne:}
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX2 - X1), x1 := WindowX2}
- MOV AX,SI {SI = WindowX2}
- SUB AX,x1
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,SI
- JMP @Punkt1
-
- @CL5:
- TEST AL,NOT CodeOben {Punkt1 oberhalb des Windows?}
- JZ @CL6 {nein}
- {ja, berechne:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY1 - y1), y1 := WindowY1 }
- MOV AX,DI {DI = WindowY1}
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- MOV y1,DI
- JMP @Punkt1
-
- @CL6:
- TEST AL,NOT CodeUnten {Punkt unterhalb des Windows?}
- JZ @Punkt1 {nein}
- {ja, berechne:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY2 - y1), y1 := WindowY2 }
- MOV AX,WindowY2
- PUSH AX
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- POP AX
- MOV y1,AX
- JMP @Punkt1
-
- {Hier gilt: die beiden Punkte wurden auf den sichtbaren Bereich zurecht-}
- {gestutzt; sollte die Gerade keinen sichtbaren Teil besitzen, so wurde }
- {direkt zu @LineReady verzweigt! }
- @DrawLine:
- PUSH BP
- MOV Steigung,0 {Flag zurücksetzen}
- MOV CX,x2
- SUB CX,x1 {Punkt1 rechts von Punkt2 ?}
- JGE @posDX {nein}
- NEG CX {ja, Punkte vertauschen}
- MOV AX,x1
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
-
- @posDX:
- MOV DI,y1
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y1 * LINESIZE}
- MOV AX,x1
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y1 * LINESIZE + (x1 DIV 4) }
-
- AND BX,3 {BX := (x1 AND 4) }
- MOV DH,[OFFSET TranslateTab + BX] {Maske für VRAM-Zugriff holen}
- MOV DL,2
-
- MOV BX,pa {BX = Zeichenseite}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr -StartIndex*2]
-
- {ES:DI=Zeiger auf Grafikadresse von Punkt1, DX=Zugriffsmaske dafür}
- MOV SI,LINESIZE
- MOV BX,y2
- SUB BX,y1 {Punkt1 unterhalb von Punkt2 ?}
- JG @posDY {nein}
- NEG BX {ja, deltaY und Zeileninkrement negieren}
- NEG SI
-
- @posDY:
- CMP BX,CX {deltaY > deltaX ?}
- JLE @flach {nein: geringe Steigung, <=1 }
- XCHG BX,CX {ja, deltas vertauschen und Flag setzen}
- MOV Steigung,1
-
- {Jetzt Bresenham-Parameter berechnen: 2 * DY, 2 * DY - DX, 2 * (DY - DX) }
- @flach:
- SHL BX,1
- MOV DY_mal2,BX
- SUB BX,CX
- MOV BP,BX {BP := 2 * DY - DX}
- SUB BX,CX
- MOV DY_m_DX_mal2,BX
- INC CX {CX := Anzahl Pixel}
- MOV BL,Color
- MOV BH,1
- CMP Steigung,0 {steile Linie?}
- JNZ @high1 {ja}
-
- @low1: {nein}
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX {richtige Bitplane anwählen}
- MOV DX,AX {Maske wieder nach DX retten}
- MOV AL,BL {Farbe für Punkt holen}
- STOSB {Punkt setzen}
- SHL DH,1 {Maske für nächsten Punkt berechnen }
- CMP DH,16 {noch mit derselben Adresse ansprechbar?}
- JE @nextbyte1 {nein, Adr. muß(te) um 1 erhöht werden }
- DEC DI {ja, Erhöhung von DI rückgängig machen }
- @low1b:
- OR BP,BP
- JGE @low2
- ADD BP,DY_mal2
- LOOP @low1
- JMP @raus
- @nextbyte1:
- MOV DH,BH {Maske auf 1 zurücksetzen}
- JMP @low1b {Rest wie gehabt}
-
- @low2:
- ADD BP,DY_m_DX_mal2
- ADD DI,SI
- LOOP @low1
- JMP @raus
-
-
- @high1:
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX
- MOV DX,AX
- MOV AL,BL
- @high1b:
- OR BP,BP
- JGE @high2
- ADD BP,DY_mal2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1b
- JMP @raus
-
- @high2:
- ADD BP,DY_m_DX_mal2
- SHL DH,1
- CMP DH,16
- JE @nextbyte2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1
- JMP @raus
- @nextbyte2:
- MOV DH,BH
- STOSB
- ADD DI,SI
- LOOP @high1
-
- @raus:
- POP BP
- @LineReady:
- END;
- END;
-
- FUNCTION GetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
- { PAGEADR= Grafikseite(nsegment), aus der gelesen werden soll }
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke }
- {out: Farbe des Punktes}
- {rem: Liegt der Punkt außerhalb des sichtbaren Bereichs, so wird }
- { "0" als Ergebniswert zurückgeliefert}
- { Achtung! Da PAGEADR immer die nichtsichtbare Grafikseite }
- { bezeichnet, liest diese Routine auch von dort die Punkte ein!}
- ASM
- XOR AL,AL {AL mit 0 vorbesetzen}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BL,3 {BL = X MOD 4 = Leseplane}
- MOV AL,4
- MOV AH,BL
- MOV DX,3CEh
-
- MOV ES,PAGEADR
- CLI
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
-
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke }
- {out: Farbe des Punktes der Hintergrundseite}
- {rem: Liegt der Punkt außerhalb des sichtbaren Bereichs, so wird }
- { "0" als Ergebniswert zurückgeliefert}
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die }
- { Routine nur für den Hintergrundmodus STATIC sinnvoll! }
- { Falls EMS verwendet wird, so muß die aufrufende Routine }
- { sicherstellen, daß im EMS-Pageframe die benötigten Daten }
- { stehen (per "IF EMSused THEN EnsureEMSConsistency()" Aufruf)}
- ASM
- XOR AL,AL {AL mit 0 vorbesetzen}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, da Worteinträge}
- ADD DI,[OFFSET BACKTab + BX] {Maske für Zugriff holen: BX * 16000}
- MOV ES,BACKGNDADR
- MOV AL,ES:[DI]
- @offscrn:
- END;
-
- FUNCTION PageGetPixel(x,y:INTEGER; pa:WORD):BYTE; ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
- { pa = Grafikseite (0..3), von der der Punkt ausgelesen }
- { werden soll}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke }
- {out: Farbe des Punktes der Hintergrundseite}
- {rem: Liegt der Punkt außerhalb des sichtbaren Bereichs, so wird }
- { "0" als Ergebniswert zurückgeliefert}
- { Soll von der gerade SICHTBAREN Seite gelesen werden, so ist }
- { beim Aufruf als Seite "1-PAGE" anzugeben! }
- { Sinnvolle Werte für "pa" sind nur 0 und 1 (und evtl. BACK- }
- { GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es }
- { findet jedoch keine Überprüfung statt!}
- ASM
- CMP pa,BACKGNDPAGE
- JNE @doit
- PUSH x
- PUSH y
- CALL BackgroundGetPixel
- JMP @offscrn
-
- @doit:
- XOR AL,AL {AL mit 0 vorbesetzen}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BL = X MOD 4 = Leseplane; BH = 0}
- MOV AL,4
- MOV AH,BL
- MOV BX,pa {BX = Grafikseite}
- AND BX,3 {nur Seiten 0..3}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr-StartIndex*2]
-
- CLI
- MOV DX,3CEh
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
-
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
- { color = Farbwert für den zu zeichnenden Punkt}
- { 1-PAGE = Grafikseite, auf der gezeichnet werden soll}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
- { WinClip= TRUE, wenn Linie auf Win* Fenster geclippt werden soll}
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = Fenster für evtl. Clipping}
- {out: - }
- {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet }
- { und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
- { Der Punkt wird NICHT automatisch in den Hintergrundspeicher über- }
- { nommen, d.h.: er ist nur einen Animationszyklus lang sichtbar! }
- { (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
- { zuführen, da der gezeichnete Punkt sonst sofort wieder verschwindet) }
- ASM
- CMP WinClip,TRUE
- JE @goClip
-
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
-
- MOV BX,1 {ES := Segment_Adr[1-PAGE], denn 1-PAGE = sichtbare Seite}
- SUB BX,PAGE
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr-StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {ab 386 schneller als STOSB!}
- STI
- JMP @ende
-
- @goClip: {hierher, wenn Clipping auf Fenster}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- CMP DI,WinYMIN
- JL @offscrn
- CMP DI,WinYMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- CMP BX,WinXMIN
- JL @offscrn
- CMP BX,WinXMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
-
- MOV BX,1 {ES := Segment_Adr[1-PAGE], denn 1-PAGE = sichtbare Seite}
- SUB BX,PAGE
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr-StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {ab 386 schneller als STOSB!}
- STI
- @offscrn:
- @ende:
- END;
-
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
- { color = Farbwert für den zu zeichnenden Punkt}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
- { WinClip=TRUE, wenn Linie auf Win* Fenster geclippt werden soll}
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = Fenster für evtl. Clipping}
- {out: - }
- {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet und}
- { in den Hintergrund gezeichnet (sofern er im sichtbaren Bereich liegt) }
- { Der Punkt wird NICHT sofort sichtbar, sondern erst nach einem Anima- }
- { tionszyklus (dann aber permanent) (Deshalb ist es sinnvoll, diese Rou- }
- { tine VOR dem Aufruf von ANIMATE auszuführen, so daß evtl. Änderungen }
- { des Hintergrundes "sofort" sichtbar werden!) }
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwendung }
- { der Routine nur für den Hintergrundmodus STATIC sinnvoll!}
- { Falls EMS verwendet wird, so muß die aufrufende Routine }
- { sicherstellen, daß im EMS-Pageframe die benötigten Daten }
- { stehen (per "IF EMSused THEN EnsureEMSConsistency()" Aufruf)}
- ASM
- CMP WinClip,TRUE
- JE @goClip
-
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, da Worteinträge}
- ADD DI,[OFFSET BACKTab + BX] {Maske für Zugriff holen: BX * 16000}
- MOV ES,BACKGNDADR
- MOV AL,color
- MOV ES:[DI],AL {ab 386 schneller als STOSB!}
- JMP @ende
-
- @goClip: {hierher, wenn Clipping auf Fenster}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- CMP DI,WinYMIN
- JL @offscrn
- CMP DI,WinYMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- CMP BX,WinXMIN
- JL @offscrn
- CMP BX,WinXMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, da Worteinträge}
- ADD DI,[OFFSET BACKTab + BX] {Maske für Zugriff holen: BX * 16000}
- MOV ES,BACKGNDADR
- MOV AL,color
- MOV ES:[DI],AL {ab 386 schneller als STOSB!}
- @offscrn:
- @ende:
- END;
-
- PROCEDURE PagePutPixel(x,y:INTEGER; color:BYTE; pa:WORD); ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
- { color = Farbwert für den zu zeichnenden Punkt}
- { pa = Grafikseite (0..3), auf der gezeichnet werden soll }
- { PAGEADR= Grafikseite(nsegment), auf der gezeichnet werden soll}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
- { WinClip= TRUE, wenn Linie auf Win* Fenster geclippt werden soll}
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = Fenster für evtl. Clipping}
- {out: - }
- {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet }
- { und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
- { Soll auf die gerade SICHTBARE Seite gezeichnet werden, so ist}
- { beim Aufruf als Seite "1-PAGE" anzugeben! }
- { Auch hier gilt, daß der gezeichnete Punkt NICHT automatisch }
- { in den Hintergrundspeicher übernommen wird, d.h.: er ist nur }
- { bis zum nächsten Animationszyklus (= Aufruf von ANIMATE) }
- { sichtbar! (Deshalb ist es sinnvoll, diese Routine NACH Aufruf}
- { von ANIMATE auszuführen, da der gezeichnete Punkt sonst so- }
- { fort wieder verschwindet!) }
- { Sinnvolle Werte für "pa" sind nur 0 und 1 (und evtl. BACK- }
- { GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es }
- { findet jedoch keine Überprüfung statt!}
- ASM
- CMP pa,BACKGNDPAGE
- JNE @doit
- PUSH x
- PUSH y
- PUSH WORD PTR color
- CALL BackgroundPutPixel
- JMP @offscrn
-
- @doit:
- CMP WinClip,TRUE
- JE @goClip
-
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV BX,pa {BX = Grafikseite}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr+StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {ab 386 schneller als STOSB!}
- STI
- JMP @ende
-
- @goClip: {hierher, wenn Clipping auf Fenster}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- CMP DI,WinYMIN
- JL @offscrn
- CMP DI,WinYMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- CMP BX,WinXMIN
- JL @offscrn
- CMP BX,WinXMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, Koordinaten zulässig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV BX,pa {BX = Grafikseite}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr+StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {ab 386 schneller als STOSB!}
- STI
- @offscrn:
- @ende:
- END;
-
- PROCEDURE LoadFont(s:STRING);
- { in: s = Name der zu ladenden Fontdatei, '' für: interner Font}
- { FontType = Typ des aktuellen Fonts}
- {out: CurrentFont=Zeiger auf neuen Font }
- { FontType = Typ des geladenen Fonts}
- { FontHeight=dessen Höhe in Zeilen }
- { FontWidth =dessen Breite in Pixeln}
- { FontProportion = TagProportional, falls Proportionalschrift}
- { FontWidthTable[] = Fontweite für jeden Buchstaben}
- {rem: Da initial "ResetToInternalFont" aufgerufen wurde, hat FontType}
- { bei Aufruf dieser Routine _immer_ einen definierten Wert! }
-
- PROCEDURE ResetToInternalFont;
- VAR i,j:BYTE;
- BEGIN
- IF CurrentFont<>NIL {allererster Aufruf?}
- THEN BEGIN {nein!}
- IF FontType=TagMonoFont
- THEN FreeMem(CurrentFont,SizeOf(MonoFont))
- ELSE IF FontType=TagColorFont
- THEN FreeMem(CurrentFont,SizeOf(ColorFont))
- END;
- IF MaxAvail<SizeOf(MonoFont)
- THEN BEGIN {nicht mal genug Speicher für internen Font!}
- Error:=Err_NotEnoughMemory;
- exit
- END;
- GetMem(CurrentFont,SizeOf(MonoFont));
- FontType:=TagMonoFont;
- FontWidth:=6;
- FontHeight:=6;
- FontProportion:=0;
- FillChar(FontWidthTable,SizeOf(FontWidthTable),FontWidth);
- FOR i:=0 TO 255 DO
- FOR j:=0 TO FontHeight-1 DO
- MonoFont(CurrentFont^)[i][j]:=internalFont[i][j]
- END;
-
- VAR f:FileOfByte;
- CONST Tag:STRING='FNT';
- VAR Header:STRING[3];
- size,i,j:WORD;
- newFontWidth,newFontHeight,newFontType,newFontProp:BYTE;
- tempName:STRING;
- BEGIN
- IF s=''
- THEN BEGIN {umschalten auf internen Font}
- ResetToInternalFont;
- exit
- END;
-
- tempName:=FindFile(s);
- IF tempName<>'' THEN s:=tempName;
-
- {Fontdatei öffnen und Header auslesen:}
- _Assign(f,s);
- {$I-}
- _Reset(f);
- Header[0]:=CHAR(Length(Tag));
- _BlockRead(f,Header[1],Length(Tag));
- _BlockRead(f,newFontWidth,1);
- _BlockRead(f,newFontHeight,1);
- _BlockRead(f,newFontType,1);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (IOresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- exit;
- END;
-
- newFontProp:=newFontType AND TagProportional; {<>0, falls proportional}
- newFontType:=newFontType AND Pred(TagProportional);
-
- size:=Length(Tag)+3; {Länge des Headers}
- IF newFontType=TagMonoFont
- THEN inc(size,((newFontWidth+7) SHR 3)*newFontHeight SHL 8)
- ELSE inc(size,newFontWidth*newFontHeight SHL 8); {256 Zeichen}
-
- IF newFontProp=TagProportional THEN inc(size,256); {Fontweiten}
-
- IF (Header<>Tag) OR
- ( (newFontType<>TagMonoFont) AND (newFontType<>TagColorFont) ) OR
- (newFontWidth>MaxFontWidth) OR
- (newFontHeight>MaxFontHeight) OR
- (_FileSize(f)<>size)
- THEN BEGIN {kein FONT-File}
- Error:=Err_NoFont;
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- CompressError:=CompressErr_NoError;
- exit
- END;
-
- IF newFontType=TagMonoFont
- THEN size:=SizeOf(MonoFont)
- ELSE size:=SizeOf(ColorFont);
-
- {Nun alten Speicher freigeben und neuen besorgen:}
- IF FontType<>newFontType
- THEN BEGIN {nur nötig, wenn alter und neuer Font verschieden sind}
- IF FontType=TagMonoFont THEN FreeMem(CurrentFont,SizeOf(MonoFont))
- ELSE {FontType=TagColorFont} FreeMem(CurrentFont,SizeOf(ColorFont));
- IF MaxAvail<size
- THEN BEGIN {nicht genug Speicher}
- Error:=Err_NotEnoughMemory;
- ResetToInternalFont;
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- exit
- END;
- GetMem(CurrentFont,size)
- END;
-
- FontWidth :=newFontWidth;
- FontHeight :=newFontHeight;
- FontType :=newFontType;
- FontProportion:=newFontProp;
-
- IF FontType=TagMonoFont
- THEN BEGIN
- FOR i:=0 TO 255 DO
- BEGIN
- Fillchar(MonoFont (CurrentFont^)[i],SizeOf(MonoFontChar),0);
- FOR j:=0 TO FontHeight-1 DO
- {$I-}
- _BlockRead(f,MonoFont(CurrentFont^)[i][j],(FontWidth+7) SHR 3);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- END;
- END
- ELSE FOR i:=0 TO 255 DO
- FOR j:=0 TO FontHeight-1 DO
- {$I-}
- _BlockRead(f,ColorFont(CurrentFont^)[i][j],FontWidth);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- {$I-}
- IF FontProportion=TagProportional
- THEN _BlockRead(F,FontWidthTable,SizeOf(FontWidthTable))
- ELSE FillChar(FontWidthTable,SizeOf(FontWidthTable),FontWidth);
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- CompressError:=CompressErr_NoError; {evtl. Compress-Fehler zurücksetzen}
- END;
-
- FUNCTION OutTextLength(s:STRING):WORD;
- { in: s = Textstring}
- { Font* = Fontbeschreibungsdaten}
- {out: Breite des auszugebenden Textes in _Pixeln_; hierbei werden}
- { Proportionalfonts korrekt behandelt}
- VAR i:BYTE;
- temp:WORD;
- BEGIN
- IF FontProportion=TagProportional
- THEN BEGIN
- temp:=0;
- FOR i:=1 TO length(s) DO inc(temp,FontWidthTable[BYTE(s[i])]);
- END
- ELSE temp:=FontWidth*length(s);
- OutTextLength:=temp
- END;
-
- PROCEDURE OutTextXY(x,y:INTEGER; pa:WORD; s:STRING);
- { in: (x,y) = (virtuelle) Startkoordinaten des auszugebenden Textes}
- { s = auszugebender Textstring }
- { pa = Grafikseite, auf der der Text ausgegeben werden soll }
- { GraphTextColor=Textfarbe }
- { GraphTextBackground=Farbe für Texthintergrund;ist dieser Wert }
- { =GraphTextColor, so werden nur die Textpixel gezeichnet}
- { und die umgebenden Pixel unverändert gelassen (=nor- }
- { males Verhalten von TurboPascal's OutText-Routinen!) }
- { GraphTextOrientation="vertical" oder "horizontal" }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- { Font* = Fontbeschreibungsdaten}
- {out: Text wurde auf dem Bildschirm ausgegeben }
- VAR offs,z,bit,i,CharWidth:BYTE;
- data1:MonoFontchar;
- data2:ColorFontChar;
- b:WORD;
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END;
- IF (pa=BACKGNDPAGE) AND EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- offs:=MaxFontWidth-FontWidth;
- IF (FontType=TagMonoFont)
- THEN FOR i:=1 TO Length(s) DO
- BEGIN
- data1:=MonoFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=WORD(data1[z]);
- FOR bit:=0 TO CharWidth-1 DO
- IF b and FontMask[bit+offs]<>0
- THEN PagePutPixel(x+bit,y+z,GraphTextColor,pa)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- ELSE FOR i:=1 TO Length(s) DO
- BEGIN
- data2:=ColorFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- b:=data2[z][bit];
- IF b<>0 THEN PagePutPixel(x+bit,y+z,b,pa)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- END;
-
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- {rem: Wie OutTextXY(), aber es wird in den Hintergrund geschrieben und}
- { nicht in die durch PAGEADR spezifizierte Seite! }
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die }
- { Routine nur für den Hintergrundmodus STATIC sinnvoll!}
- VAR offs,z,bit,i,CharWidth:BYTE;
- data1:MonoFontchar;
- data2:ColorFontChar;
- b:WORD;
- BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- offs:=MaxFontWidth-FontWidth;
- IF (FontType=TagMonoFont)
- THEN FOR i:=1 TO Length(s) DO
- BEGIN
- data1:=MonoFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=WORD(data1[z]);
- FOR bit:=0 TO CharWidth-1 DO
- IF b and FontMask[bit+offs]<>0
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextColor)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- ELSE FOR i:=1 TO Length(s) DO
- BEGIN
- data2:=ColorFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- b:=data2[z][bit];
- IF b<>0 THEN BackgroundPutPixel(x+bit,y+z,b)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- END;
-
- PROCEDURE MakeTextSprite(s:STRING; nr:WORD);
- { in: s = in ein Sprite umzuwandelnder Text}
- { nr = SpriteLADEnummer für das zu generierende Sprite}
- { Font*, CurrentFont = aktueller Font}
- { GraphTextOrientation = Fontausrichtung}
- {out: Sprite?[nr] wurde so definiert, daß es den Textinhalt von "s" als}
- { Sprite enthält}
- {rem: Die Routine verhält sich wie LoadSprite()}
- CONST DefaultHeader:SpriteHeader=
- (Zeiger_auf_Plane:(0,0,0,0);
- Breite_in_4er_Gruppen:0;
- Hoehe_in_Zeilen:0;
- Translate:(1,2,4,8);
- SpriteLength:0;
- Dummy:(0,0,0,0,0,0,0,0,0,0);
- Kennung:'KR';
- Version:1;
- Modus:Display_NORMAL;
- ZeigerL:0;
- ZeigerR:0;
- ZeigerO:0;
- ZeigerU:0
- );
- VAR header:SpriteHeader;
- p1,p2:POINTER;
- segm,offs,b:WORD;
- x,y,i:INTEGER;
- z,wert,bit,CharWidth:BYTE;
- data1:MonoFontchar;
- data2:ColorFontChar;
- BEGIN
- IF (nr=0) or (nr>LoadMAX)
- THEN BEGIN
- Error:=Err_InvalidSpritenumber;
- Exit
- END;
- header:=DefaultHeader; {Schablone übernehmen}
- WITH header DO
- BEGIN
- IF GraphTextOrientation=horizontal
- THEN BEGIN {Sprite ist nur 1 Charzelle hoch}
- Hoehe_in_Zeilen:=FontHeight;
- Breite_in_4er_Gruppen:=(OutTextLength(s)+3) SHR 2
- END
- ELSE BEGIN {Sprite ist nur 1 Charzelle breit}
- Hoehe_in_Zeilen:=FontHeight*Length(s);
- Breite_in_4er_Gruppen:=(FontWidth+3) SHR 2
- END;
- SpriteLength:=Kopf+ {Spriteheader-Größe}
- 2*(2*Hoehe_in_Zeilen)+ {li. & re. Begrenzungen}
- 2*(2*4*Breite_in_4er_Gruppen)+ {ob. & un. Begrenzungen}
- Breite_in_4er_Gruppen*4*Hoehe_in_Zeilen; {Data}
- IF (Breite_in_4er_Gruppen*Hoehe_in_Zeilen=0)
- OR (SpriteLength>65521-15) {GetMem-Obergrenze=65521}
- THEN BEGIN
- Error:=Err_NoSprite;
- Exit
- END;
- {noch genug Platz da?}
- IF (Header.SpriteLength+15>MaxAvail+SPRITESIZE[nr])
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- Exit
- END
- ELSE FreeSpriteMem(nr); {evtl. alten Speicher freigeben}
-
- getmem(p1,Header.SpriteLength+15); {genug Platz reservieren}
- SPRITESIZE[nr]:=Header.SpriteLength+15;
- SPRITEPTR [nr]:=p1;
- IF (LONGINT(p1) mod 16)=0
- THEN p2:=p1 {p2 auf Segmentgrenze bringen}
- ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
- segm:=LONGINT(p2) SHR 16 +(LONGINT(p2) AND 65535) SHR 4;
- SPRITEAD[nr]:=segm;
-
- ZeigerL:=Kopf;
- ZeigerR:=ZeigerL+Hoehe_in_Zeilen*2;
- ZeigerO:=ZeigerR+Hoehe_in_Zeilen*2;
- ZeigerU:=ZeigerO+(Breite_in_4er_Gruppen*4)*2;
- FOR i:=0 TO 3 DO
- Zeiger_auf_Plane[i]:=ZeigerU+(Breite_in_4er_Gruppen*4)*2+
- i*Breite_in_4er_Gruppen*Hoehe_in_Zeilen;
- FOR i:=0 TO Hoehe_in_Zeilen-1 DO
- BEGIN
- MEMW[segm:ZeigerL +i SHL 1]:=+16000;
- MEMW[segm:ZeigerR +i SHL 1]:=WORD(-16000);
- END;
- FOR i:=0 TO Breite_in_4er_Gruppen*4-1 DO
- BEGIN
- MEMW[segm:ZeigerO +i SHL 1]:=+16000;
- MEMW[segm:ZeigerU +i SHL 1]:=WORD(-16000);
- END;
-
- MOVE(Header,p2^,Kopf); {Spriteheader auf Heap bringen}
-
- {jetzt Spritedaten berechnen: dazu Pixel in Speicher "zeichnen"}
- offs:=MaxFontWidth-FontWidth; x:=0; y:=0;
- IF (FontType=TagMonoFont)
- THEN FOR i:=1 TO Length(s) DO
- BEGIN
- data1:=MonoFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=WORD(data1[z]);
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- IF b and FontMask[bit+offs]<>0
- THEN wert:=GraphTextColor
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN wert:=GraphTextBackground
- ELSE wert:=0;
- {Punkt (a,b) -> b*Breite_in_4er_Gruppen+(x div 4) auf Plane x mod 4}
- MEM[segm:Zeiger_auf_Plane[(x+bit) AND 3]+
- (y+z)*Breite_in_4er_Gruppen+
- (x+bit) SHR 2]:=wert;
- IF wert<>0
- THEN BEGIN {Grenzen evtl. neu berechnen}
- IF x+bit<INTEGER(MEMW[segm:ZeigerL +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerL +(y+z) SHL 1]:=x+bit;
- IF x+bit>INTEGER(MEMW[segm:ZeigerR +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerR +(y+z) SHL 1]:=x+bit;
- IF y+z<INTEGER(MEMW[segm:ZeigerO +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerO +(x+bit) SHL 1]:=y+z;
- IF y+z>INTEGER(MEMW[segm:ZeigerU +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerU +(x+bit) SHL 1]:=y+z;
- END;
- END;
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- ELSE FOR i:=1 TO Length(s) DO
- BEGIN
- data2:=ColorFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- b:=data2[z][bit];
- IF b<>0 THEN wert:=b
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN wert:=GraphTextBackground
- ELSE wert:=0;
- {Punkt (a,b) -> b*Breite_in_4er_Gruppen+(x div 4) auf Plane x mod 4}
- MEM[segm:Zeiger_auf_Plane[(x+bit) AND 3]+
- (y+z)*Breite_in_4er_Gruppen+
- (x+bit) SHR 2]:=wert;
-
- IF wert<>0
- THEN BEGIN {Grenzen evtl. neu berechnen}
- IF x+bit<INTEGER(MEMW[segm:ZeigerL +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerL +(y+z) SHL 1]:=x+bit;
- IF x+bit>INTEGER(MEMW[segm:ZeigerR +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerR +(y+z) SHL 1]:=x+bit;
- IF y+z<INTEGER(MEMW[segm:ZeigerO +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerO +(x+bit) SHL 1]:=y+z;
- IF y+z>INTEGER(MEMW[segm:ZeigerU +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerU +(x+bit) SHL 1]:=y+z;
- END;
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
-
- END; {of WITH}
-
- END;
-
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; ASSEMBLER;
- { in: s1,s2 = Spritepositionsnummern zweier Sprites}
- { SpriteN[s1],SpriteX[s1],SpriteY[s1] = Spritedaten von Sprite s1 }
- { SpriteN[s2],SpriteX[s2],SpriteY[s2] = Spritedaten von Sprite s2 }
- {out: TRUE/FALSE für "Sprites kollidieren"/"Sprites kollidieren nicht" }
- {rem: Diese Überprüfung geschieht punktgenau und ist unabhängig davon, }
- { ob die Sprites z.Z. gerade sichtbar sind oder nicht. }
- { Inaktive Sprites (SpriteN[s?]=0) können nicht miteinander kollid. }
- { Ein Sprite kann nicht mit sich selbst kollidieren (s1=s2 -> FALSE) }
- ASM
- MOV SI,s1 {1.Parameter s1 vom Stack holen}
- MOV DI,s2 {2.Parameter s2 vom Stack holen}
- CMP SI,DI
- JE @NOHIT1 {Sprite kann sich nicht selbst treffen}
- SHL SI,1
- mov cx,[SI + OFFSET SpriteN]
- jcxz @NOHIT1 {Sprite <>0, d.h.: überhaupt aktiv?}
- SHL DI,1
- MOV BX,[DI + OFFSET SpriteN]
- OR BX,BX {dto. für anderes Sprite}
- JNE @PRUEF2
- @NOHIT1:
- JMP @NOHIT7 {inaktive Sprites können auch nicht}
- {kollidieren -> FALSE zurückgeben }
- {hier: SI (DI) = Zeiger auf 1. (2.) Sprite in ?WRTD[..] ,}
- { CX (BX) = Spritenummer von Sprite 1 (2) }
- {(etwas später wird dann DS (ES) = Segment der Spr.daten von Spr.1 (2) )}
- @PRUEF2:
- MOV AX,[SI + OFFSET SpriteY]
- MOV DX,[DI + OFFSET SpriteY]
- mov si,[SI + OFFSET SpriteX] {SI = x1}
- mov di,[DI + OFFSET SpriteX] {DI = x2}
- shl bx,1 {BX = Spritenummer2 * 2}
- mov es,[BX + OFFSET SPRITEAD] {ES = Segment der Spritedaten2}
- mov bx,cx {(CX = Spritenummer1)}
- shl bx,1 {BX = Spritenummer1 * 2}
- MOV ds,[BX + OFFSET SPRITEAD]
-
- mov [y1],ax
- mov [y2],dx
- sub dx,ax
- mov CS:WORD PTR @y2_y1+1,dx
- mov [x1],si
- mov [x2],di
- mov dx,di
- sub dx,si
- mov CS:WORD PTR @x2_x1+1,dx
- mov ax,es:[Left] {AX = Zeiger auf linke Randdaten}
- mov CS:WORD PTR @lirand2+1,ax
- mov ax,es:[Right] {AX = Zeiger auf rechte Randdaten}
- mov CS:WORD PTR @rerand2+1,ax
- mov ax,es:[Top] {AX = Zeiger auf obere Randdaten}
- mov CS:WORD PTR @orand2+1,ax
- mov ax,es:[Bottom] {AX = Zeiger auf untere Randdaten}
- mov CS:WORD PTR @urand2+1,ax
- mov ax,es:[Breite] {AX = max. Breite in 4er-Gruppen}
- shl al,1
- shl al,1
- mov CS:WORD PTR @breite2+1,ax {*4 = Breite in Punkten}
- mov ax,es:[Hoehe]
- mov CS:WORD PTR @hoehe2+1,ax {Höhe von Sprite2 in Punkten}
-
- MOV AX,[Left] {AX = Zeiger auf linke Randdaten}
- MOV CS:WORD PTR @LIRAND1+1,AX
- MOV AX,[Right] {AX = Zeiger auf rechte Randdaten}
- MOV CS:WORD PTR @RERAND1+1,AX
- MOV AX,[Top] {AX = Zeiger auf obere Randdaten}
- MOV CS:WORD PTR @ORAND1+1,AX
- MOV AX,[Bottom] {AX = Zeiger auf untere Randdaten}
- MOV CS:WORD PTR @URAND1+1,AX
- MOV BX,[Breite] {BX = max. Breite in 4er-Gruppen}
- SHL BX,1
- SHL BX,1 {*4 = Breite in Punkten}
- MOV CS:WORD PTR @BREITE1+2,BX
-
- lea bx,[si+bx-1] {BX := x1 + breite1 - 1 (=x1last)}
- @breite2:
- mov bp,1234h {Dummywert}
- mov cx,bp {CX = breite2 brauchen wir später nochmal}
- lea bp,[di+bp-1] {BP := x2 + breite2 - 1 (=x2last)}
- cmp bx,bp
- jle @noex1
- mov bp,bx
- @noex1: {hier: BP = max(x1last,x2last) (=maxx)}
- cmp si,di
- jle @X1_klgl_X2
- xchg si,di
- @X1_klgl_X2: {hier: SI = min(x1,x2) (=minx)}
- stc
- sbb si,bp {SI := minx - maxx - 1 = - (maxx - minx + 1)}
- @breite1:
- add cx,1234h {(Dummywert) CX := breite1 + breite2}
- add cx,si {CX := breite1 + breite2 - (maxx - minx + 1)}
- dec cx {CX := breite1 + breite2 - (maxx - minx + 1) - 1 (=ueberlappx - 1)}
- js @NOHIT2 {kein Treffer, wenn ueberlappx <= 0}
- mov [ueberlappx_1],cx
-
- mov ax,[Hoehe]
- mov bx,ax {BX := hoehe1}
- mov di,[y1] {DI := y1}
- add ax,di {AX := y1 + hoehe1}
- dec ax {AX := y1 + hoehe1 - 1 (=y1last)}
- @hoehe2:
- mov si,1234h
- mov dx,[y2]
- add dx,si {DX := y2 + hoehe2}
- dec dx {DX := y2 + hoehe2 - 1 (=y2last)}
- cmp ax,dx
- jge @noex2
- mov ax,dx
- @noex2: {hier: AX = max(y1last,y2last) (=maxy)}
- mov dx,[y2]
- cmp di,dx {(DI = y1)}
- jle @noex3
- mov di,dx
- @noex3: {hier: DI = min(y1,y2) (=miny)}
- sub di,ax {DI := miny - maxy = - (maxy - miny)}
- lea ax,[bx+si-2] {AX := hoehe1 + hoehe2 - 2}
- add ax,di {AX := hoehe1 + hoehe2 - (maxy - miny + 1) - 1 (=ueberlappy - 1)}
- js @NOHIT2 {kein Treffer, wenn ueberlappy <= 0}
- mov [ueberlappy_1],ax
-
- {hier: AX = ueberlappy - 1, CX = ueberlappx - 1}
- @x2_x1:
- mov dx,1234h {Dummywert}
- xor bx,bx {ab jetzt: BX = 0 !}
- or dx,dx
- js @X2_X1_kl_0 {if x2 - x1 >= 0 then...}
- mov [hit2xfirst],bx {...hit2xfirst := 0}
- mov [hit1xfirst],dx {...hit1xfirst := x2 - x1}
- jmp @Yhits {SHORT}
-
- {Sprungleiste für NOHIT (paßt hier gut hin)}
- @NOHIT2:
- JMP @NOHIT7
-
- {jetzt wieder normales Programm}
- @X2_X1_kl_0: {else (x2 - x1 < 0)...}
- mov [hit1xfirst],bx {...hit1xfirst := 0}
- neg dx {DX := x1 - x2}
- mov [hit2xfirst],dx {...hit2xfirst := x1 - x2}
-
- @Yhits: {hier: AX = ueberlappy - 1}
- @y2_y1:
- mov dx,1234h {Dummywert}
- or dx,dx
- js @Y2_Y1_kl_0 {if y2 - y1 >= 0 then...}
- mov [hit2yfirst],bx {...hit2yfirst := 0}
- mov [hit1yfirst],dx {...hit1yfirst := y2 - y1}
- jmp @iterate {SHORT}
- @Y2_Y1_kl_0: {else (y2 - y1 < 0)...}
- mov [hit1yfirst],bx {...hit1yfirst := 0}
- neg dx {DX := y1 - y2}
- mov [hit2yfirst],dx {...hit2yfirst := y1 - y2}
-
- {Nun werden iterativ die überlappenden Zeilen und Spalten exakt geprüft}
- @iterate:
- mov cx,[ueberlappy_1] {Anzahl der zu vergleichenden Zeilen -1}
- shl cx,1 {*2, da Word-Werte!}
- @lirand1:
- mov si,1234h {Dummywert}
- @lirand2:
- mov di,1234h {Dummywert}
- @rerand1:
- mov bx,1234h {Dummywert}
- @rerand2:
- mov bp,1234h {Dummywert}
- sub bx,si {BX := rerand1 - lirand1}
- sub bp,di {BP := rerand2 - lirand2}
- mov ax,[hit1yfirst]
- shl ax,1
- add si,ax {SI := 1.Zeile, in der Sp.1 mit Sp.2 überlappt}
- mov ax,[hit2yfirst]
- shl ax,1
- add di,ax {DI := 1.Zeile, in der Sp.2 mit Sp.1 überlappt}
- add si,cx {dto., letzte Zeile}
- add di,cx
- @one_line:
- mov ax,[si] {DS:AX := x1li[Zeile]}
- mov dx,es:[di] {ES:DX := x2li[Zeile]}
- add ax,[x1] {AX := x1li[Zeile] + x1 (=c)}
- add dx,[x2] {DX := x2li[Zeile] + x2 (=d)}
- cmp ax,dx
- jge @C_grgl_D
- mov ax,dx
- @C_grgl_D: {hier: AX = max(c,d)}
- mov cx,[si+bx] {DS:CX := x1re[Zeile]}
- mov dx,es:[di+bp] {ES:DX := x2re[Zeile]}
- add cx,[x1] {CX := x1re[Zeile] + x1 (=a)}
- add dx,[x2] {DX := x2re[Zeile] + x2 (=b)}
- cmp cx,dx
- jle @A_klgl_B
- mov cx,dx
- @A_klgl_B: {hier: CX = min(a,b)}
- cmp cx,ax {min(a,b) >= max(c,d) ?}
- jge @found_Xhit {ja: Treffer in X-Richtung gefunden!}
- dec si {nächste Zeile (-> Word-Werte!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappy_1]
- jns @one_line
- {kein Treffer in X-Richtung -> überhaupt kein Treffer!}
- jmp @NOHIT7
-
- {ansonsten: Treffer in X-Ri., jetzt noch Y-Ri. prüfen (analog zu oben) und }
- {"Treffer!" nur dann ausgeben, falls auch mind. 1 Treffer in Y-Ri. existiert}
- @found_Xhit:
- mov cx,[ueberlappx_1] {Anzahl der zu vergleichenden Spalten -1}
- shl cx,1 {*2, da Word-Werte!}
- @orand1:
- mov si,1234h {Dummywert}
- @orand2:
- mov di,1234h {Dummywert}
- @urand1:
- mov bx,1234h {Dummywert}
- @urand2:
- mov bp,1234h {Dummywert}
- sub bx,si {BX := urand1 - orand1}
- sub bp,di {BP := urand2 - orand2}
- mov ax,[hit1xfirst]
- shl ax,1 {*2, da Word-Werte!}
- add si,ax {SI := orand1 + 2 * hit1xfirst}
- mov ax,[hit2xfirst]
- shl ax,1 {*2, da Word-Werte!}
- add di,ax {DI := orand2 + 2 * hit2xfirst}
- add si,cx
- add di,cx
- @one_column: mov ax,[si] {AX := y1ob[Spalte]}
- cmp ax,16000 {Dummywert für "leere Spalte"?}
- je @next_column {ja, also sicherlich kein Treffer}
- mov dx,es:[di] {DX := y2ob[Spalte]}
- cmp dx,16000 {auch 2.Sprite prüfen: "leere Spalte"?}
- je @next_column {ja, kein Treffer}
- add ax,[y1] {AX := y1ob + y1 (=c)}
- add dx,[y2] {DX := y2ob + y2 (=d)}
- cmp ax,dx
- jge @C_grgl_D2
- mov ax,dx
- @C_grgl_D2: {hier: AX = max(c,d)}
- mov cx,[si+bx] {DS:CX := y1un[Spalte]}
- mov dx,es:[di+bp] {ES:DX := y2un[Spalte]}
- add cx,[y1] {CX := y1un + y1 (=a)}
- add dx,[y2] {DX := y2un + y2 (=b)}
- cmp cx,dx
- jle @A_klgl_B2
- mov cx,dx
- @A_klgl_B2: {hier: CX = min(a,b)}
- cmp cx,ax {min(a,b) >= max(c,d) ?}
- jge @HIT2 {ja: Treffer gefunden!}
- @next_column:
- dec si {nein, nächste Spalte (-> Word-Werte!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappx_1]
- jns @one_column
-
- @NOHIT7:
- XOR AX,AX {als Ergebnis 0 = FALSE zurückgeben}
- JMP @TREFF_END {SHORT}
- @HIT2:
- MOV AX,1 {als Ergebnis 1 = TRUE zurückgeben}
-
- @TREFF_END:
- {$IFOPT G+}
- mov bp,sp {nur nötig für Compilerschalter G+!}
- {$ENDIF}
- mov dx,seg @DATA {sonst wird BP von TP wiederhergestellt}
- mov ds,dx
- END;
-
- PROCEDURE SetSplitIndex(number:INTEGER);
- { in: number = Index-Nummer des Sprites, bis zu dem die Sprites nicht}
- { auf das Animationsfenster zurechtgeklippt werden}
- {out: - }
- {rem: Nach Aufruf dieser Routine werden SpriteN[0..number] nicht- und}
- { SpriteN[number+1..NMAX] auf das Animationsfenster zurechtgeclipt}
- { Ist number <0 oder >NMAX, so werden alle Sprites geclipt!}
- BEGIN
- IF number>NMAX THEN number:=-1;
- SplitIndex:=number;
- SplitIndex_mal2:=number*2
- END;
-
- FUNCTION GetSplitIndex:INTEGER;
- { in: - }
- {out: Momentan gesetzter Wert für SplitIndex}
- BEGIN
- GetSplitIndex:=SplitIndex
- END;
-
- PROCEDURE SetAnimateWindow(x1,y1,x2,y2:INTEGER);
- { in: (x1,y1) = linke obere Ecke des zu setzenden Animationsbereiches}
- { (x2,y2) = dto., rechte untere Ecke}
- {out: Win* wurden entsprechend neugesetzt}
- { BWin* = Backups der wichtigsten Werte}
- {rem: Die Punkte müssen in absoluten Koordinaten angegeben werden}
- { Das Fenster muß eine Mindestgröße von 32x32 Punkten haben, }
- { x1 und x2-x1+1 müssen Vielfache von 4 sein (oder werden darauf gebracht)!}
- BEGIN
- x1:=x1 AND $FFFC; {x1 auf Vielfaches von 4 bringen}
- WinXMIN:=x1; WinXMINdiv4:=x1 SHR 2;
- WinYMIN:=y1; WinYMIN_mul_LINESIZE:=y1*LINESIZE;
- WinYMINmLINESIZEaWinXMINdiv4:=WinYMIN_mul_LINESIZE+WinXMINdiv4;
- WinWidth :=succ(x2-x1) AND $FFFC; {Weite auf Vielfaches von 4 bringen}
- WinHeight:=succ(y2-y1);
- WinXMAX:=WinXMIN+WinWidth-1;
- WinYMAX:=WinYMIN+WinHeight-1;
- WinWidthDiv4:=WinWidth SHR 2;
- WinLowerRight:=(XMAX-WinXMAX) SHR 2 + (YMAX-WinYMAX)*LINESIZE;
- IF (WinXMIN<0) OR (WinYMIN<0) OR (WinWidth<32) OR (WinHeight<32) OR
- (WinXMAX>XMAX) OR (WinYMAX>YMAX)
- THEN Error:=Err_InvalidCoordinates;
-
- BWinXMIN:=WinXMIN; {Backups anlegen}
- BWinYMIN:=WinYMIN;
- BWinXMAX:=WinXMAX;
- BWinYMAX:=WinYMAX;
- BWinLowerRight:=WinLowerRight;
- BWinYMIN_mul_LINESIZE:=WinYMIN_mul_LINESIZE
- END;
-
- PROCEDURE Animate;
- { in: PAGEADR = aktuelle Grafikseite(nadresse),auf der gezeichnet werden soll}
- { BACKGNDADR = Hintergrundseite(nadresse) }
- { BACKGROUNDMODE = STATIC/SCROLLING für festen/scrollbaren Hintergrund}
- { SpriteN[] = Spritenummern der darzustellenden Sprites }
- { SpriteX[],SpriteY[] = deren zugehörigen (virtuellen) Koordinaten}
- { StartVirtualX,StartVirtualY = obere linke Bildschirmecke }
- { (PAGE = aktuell dargestellte Grafikseite) }
- { Win* = Abmessungen des Hintergrundwindows }
- {out: PAGE = 0/1, wenn PAGE vorher 1/0 war }
- { PAGEADR = neue, aktuelle Grafikseite(nadresse) }
- {rem: Animate löscht den Inhalt der alten Grafik (mithilfe der Hintergrund- }
- { seite), zeichnet alle sichtbaren Sprites, synchronisiert auf das dis- }
- { playenable-Signal und schaltet dann auf die so fertiggestellte Seite um}
- VAR leftcut,rightcut,topcut,bottomcut:WORD;
- {x,y,} xtil,ytil,actindex:INTEGER;
-
- KachelnWegLinks,KachelnWegOben,
- innerTilesX,innerTilesY,
- stepX1,stepX2,
- Xoffscreen,Yoffscreen,
- counter,
- Korrektur,
- BytesPerPlane,LINESIZE_sub_BytesPerPlane,
- leftcutDIV4,
- tempActIndex,tempDI,tempXtil,tempYtil,{tempX,tempY,}
- oldActIndex,oldDI,
- StartWritePlane,StartLesePlane: INTEGER;
- BEGIN
- IF EMSused AND (BackgroundMode=STATIC)
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- ASM
- CLD
- {zuerst das Hintergrundbild auf die aktuelle Seite kopieren:}
- CMP BackgroundMode,STATIC {welcher Hintergrundmodus?}
- JE @static_bckgnd
- JMP @scrolling_bckgnd
-
- @static_bckgnd:
- MOV BX,WinHeight
- MOV DX,WinWidth
- MOV SI,WinYMINmLINESIZEaWinXMINdiv4 {1.Start/Zieladresse}
- MOV DI,SI
-
- MOV ES,PAGEADR {Grafikseite mit Hintergrundmuster füllen}
- CMP UpdateOuterArea,0 {äußeren Hintergrund updaten?}
- MOV DS,BACKGNDADR
-
- je @skip_outer
- {inneren und äußeren Hintergrund zugleich erledigen}
- xor si,si
- xor di,di
-
- mov ax,0102h
- mov dx,3c4h
- mov bx,pagesize/2
- out dx,ax {Schreibplane 0}
- mov cx,bx
- rep movsw
- mov ah,2
- out dx,ax {Schreibplane 1}
- mov cx,bx
- xor di,di
- rep movsw
- mov ah,4
- out dx,ax {Schreibplane 2}
- mov cx,bx
- xor di,di
- rep movsw
- mov ah,8
- out dx,ax {Schreibplane 3}
- mov cx,bx
- xor di,di
- rep movsw
- mov ax,seg @data
- mov ds,ax
- dec UpdateOuterArea
- jmp @sprites_zeichnen
- @skip_outer: {nur Inneres zeichnen}
-
- PUSH BP
-
- CMP DX,XMAX+1 {Fenster durchgehend von links nach rechts?}
- JNE @innen
-
- MOV AX,0102h
- MOV DX,3C4h
- SHL BX,1 {ja, kann mit einem REP MOVSB erledigt werden}
- MOV BX,CS:[OFFSET gadr + BX] {BX := WinHeight * LINESIZE}
- MOV BP,PAGESIZE
- SUB BP,BX
-
- OUT DX,AX {Schreibplane 0 anwählen}
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- SUB DI,BX {DI zurückstellen}
- ADD SI,BP {SI auf nächste "Plane" setzen}
-
- MOV AH,2
- OUT DX,AX {Schreibplane 1 anwählen}
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- SUB DI,BX {DI zurückstellen}
- ADD SI,BP {SI auf nächste "Plane" setzen}
-
- MOV AH,4
- OUT DX,AX {Schreibplane 2 anwählen}
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- SUB DI,BX {DI zurückstellen}
- ADD SI,BP {SI auf nächste "Plane" setzen}
-
- MOV AH,8
- OUT DX,AX {Schreibplane 3 anwählen}
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
-
- jmp @end_static
-
- @innen:
- SHR DX,1
- SHR DX,1 {DX := Bytes je Zeile}
- MOV BP,LINESIZE
- SUB BP,DX {BP := Offset zur nächsten Zeile}
- MOV BH,DL
- XOR CH,CH
-
- MOV AX,0102h
- MOV DX,3C4h
- OUT DX,AX {Schreibplane 0 anwählen}
-
- MOV AH,BL
-
- PUSH SI
- PUSH DI
- @loop_innen1:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {eine Zeile übertragen}
- ADD SI,BP {auf nächste Zeile positionieren}
- ADD DI,BP
- DEC BL {eine Zeile fertig}
- JNZ @loop_innen1
- POP DI
- POP SI
-
- ADD SI,PAGESIZE
- PUSH SI
- PUSH DI
- MOV BL,AH
- MOV AH,02h
- OUT DX,AX
- MOV AH,BL
- @loop_innen2:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {eine Zeile übertragen}
- ADD SI,BP {auf nächste Zeile positionieren}
- ADD DI,BP
- DEC BL {eine Zeile fertig}
- JNZ @loop_innen2
- POP DI
- POP SI
-
- ADD SI,PAGESIZE
- PUSH SI
- PUSH DI
- MOV BL,AH
- MOV AH,04h
- OUT DX,AX
- MOV AH,BL
- @loop_innen3:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {eine Zeile übertragen}
- ADD SI,BP {auf nächste Zeile positionieren}
- ADD DI,BP
- DEC BL {eine Zeile fertig}
- JNZ @loop_innen3
- POP DI
- POP SI
-
- ADD SI,PAGESIZE
- MOV BL,AH
- MOV AH,08h
- OUT DX,AX
- MOV AH,BL
- @loop_innen4:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {eine Zeile übertragen}
- ADD SI,BP {auf nächste Zeile positionieren}
- ADD DI,BP
- DEC BL {eine Zeile fertig}
- JNZ @loop_innen4
-
- @end_static:
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- JMP @Sprites_zeichnen
-
- {---------------------------------}
-
- @scrolling_bckgnd: {ab hier: Hintergrund aus Kacheln zusammensetzen}
-
- {müssen wir das Äußere um das Animationswindow neuzeichnen?}
- cmp UpdateOuterArea,0
- je @old_scrolling_bckgnd
- {ja, aber vielleicht gar nichts zum zeichnen da?:}
- mov bx,WinHeight
- dec bx
- mov bh,bl
- mov bl,WinWidthDiv4
- mov ax,WinYMINmLINESIZEaWinXMINdiv4
- {BL=WinWidthDiv4, BH=WinHeight-1, AX=WinYMIN*LINESIZE+WinXMIN DIV 4}
- or ax,ax {linke obere Ecke des Windows = Punkt (0,0)?}
- jne @do_outer {nein: äußerer Rand zu zeichnen}
- cmp bx,YMAX SHL 8 +LINESIZE {rechte untere Ecke = Punkt (XMAX,YMAX)?}
- je @old_scrolling_bckgnd {ja, also kein äußerer Rand zu zeichnen}
-
- @do_outer: {jetzt äußeren Rand zeichnen}
- {╔════════════════╗ Einteilung des äußeren Randes in 3 Regionen}
- {║1111111111111111║ }
- {║1111111111111111║ }
- {║111┌───────┐2222║ }
- {║222│ │2222║ }
- {║222│ │2222║ }
- {║222└───────┘3333║ }
- {║3333333333333333║ }
- {║3333333333333333║ }
- {╚════════════════╝ }
-
- {BL=WinWidthDiv4, BH=WinHeight-1, AX=WinYMIN*LINESIZE+WinXMIN DIV 4}
- push bp
- push WinLowerRight
- mov bp,ax
- mov es,PAGEADR
- mov ds,BACKGNDADR
- mov dx,3C4h
- mov ax,0102h {Schreibplane 0}
- out dx,ax
- xor si,si {Region 1 beginnt bei Offset 0}
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,2 {Schreibplane 1}
- out dx,ax
- mov si,1*PAGESIZE
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,4 {Schreibplane 2}
- out dx,ax
- mov si,2*PAGESIZE
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,8 {Schreibplane 3}
- out dx,ax
- mov si,3*PAGESIZE
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,1
- out dx,ax
-
- mov al,bl
- cbw {AX:=WinWidth DIV 4; geht, weil WinWidth DIV 4 < 128 !}
- mov dl,LINESIZE
- sub dl,al {DL:=LINESIZE-WinWidth DIV 4}
- jz @region3 {Fenster geht von links nach rechts durch?}
- mov dh,bh {DH:=WinHeight-1}
- or dh,dh
- jz @region3 {Fenster nur 1 Zeile hoch?}
- xor ch,ch
- mov bx,ax
- add di,ax
- mov si,di {Zieladresse=Startadresse wg. Speicherlayout}
-
- mov bp,di
- push dx
- @region2a:
- {DL = Breite einer Zeile des Animationsfensters}
- {DH = WinHeight-1}
- {BX = WinWidth DIV 4 = Breite des Animations-Fensters DIV 4}
- {CX:=Breite einer Zeile vom rechten Rand des Animationsfensters zum}
- {linken Rand des Animationsfensters in der nächsten Zeile:}
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2a
-
- mov ax,0202h
- mov dx,3c4h
- out dx,ax
- pop dx
- push dx
- mov si,bp {SI=DI=BP für Plane #0, SI=DI+1*PAGESIZE für Plane #1, etc.}
- add si,1*PAGESIZE
- mov di,bp
- @region2b:
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2b
-
- mov ah,04h
- mov dx,3c4h
- out dx,ax
- pop dx
- push dx
- mov si,bp
- add si,2*PAGESIZE
- mov di,bp
- @region2c:
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2c
-
- mov ah,08h
- mov dx,3c4h
- out dx,ax
- pop dx
- mov si,bp
- add si,3*PAGESIZE
- mov di,bp
- @region2d:
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2d
-
-
- @region3:
- pop cx {CX:=WinLowerRight}
- jcxz @endregion3 {keine Region 3 zum zeichnen}
- mov bx,cx {Kopie davon nach BX}
- mov si,PAGESIZE
- sub si,cx {Startadresse von Region 3}
- mov di,si {Zieladresse:=Startadresse (geht wg. Speicherlayout!)}
- mov bp,di {Zieladresse merken }
- mov ax,0102h
- mov dx,3c4h
- out dx,ax
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,2
- out dx,ax
- mov cx,bx
- mov di,bp
- sub si,cx {SI auf alten Wert zurück- und dann eine "Seite" weitersetzen}
- add si,PAGESIZE
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,4
- out dx,ax
- mov cx,bx
- mov di,bp
- sub si,cx {SI auf alten Wert zurück- und dann eine "Seite" weitersetzen}
- add si,PAGESIZE
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,8
- out dx,ax
- mov cx,bx
- mov di,bp
- sub si,cx {SI auf alten Wert zurück- und dann eine "Seite" weitersetzen}
- add si,PAGESIZE
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- @endregion3:
- pop bp
- mov ax,seg @data
- mov ds,ax
- dec UpdateOuterArea {UpdateOuterArea rücksetzen}
-
- @old_scrolling_bckgnd:
-
- MOV DI,$F {häufig benutzte Konstanten}
- MOV CX,4
-
- {#Kacheln, die links _echt_ weggeschnitten sind:}
- {IF StartVirtualX+WinXMIN-BackX1<0
- THEN KachelnWegLinks:=(StartVirtualX+WinXMIN-BackX1-15) DIV 16
- ELSE KachelnWegLinks:=(StartVirtualX+WinXMIN-BackX1) DIV 16;}
- MOV AX,StartVirtualX
- ADD AX,WinXMIN
- SUB AX,BackX1
- MOV BX,AX {BX = StartVirtualX + WinXMIN - BackX1}
- SAR AX,CL
- MOV KachelnWegLinks,AX
-
- {Punkte, die der 1. (teilweise) sichtbaren Kachel links weggeschnitten sind:}
- {eigentlich: leftcut := ((StartVirtualX + WinXMIN - BackX1) MOD 16) AND $F }
- {aber das ist äquivalent zu:}
- {leftcut := (StartVirtualX + WinXMIN - BackX1) AND $F}
- {das "AND $F" ist wg. evtl. underflow <0}
- AND BX,DI
- MOV leftcut,BX
-
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- MOV leftcutDIV4,AX
-
- {Start-Leseplane links geschnittener Kacheln berechnen: leftcut AND 3}
- { Dann wird die zugehörige Maske daraus errechnet }
- MOV AH,BL {BL = leftcut}
- AND AH,3
- MOV AL,4
- MOV StartLesePlane,AX {muß im Stacksegment liegen!}
-
- {dto., für letzte (teilweise) sichtbare Kachel rechts}
- {eigentlich: rightcut := (16 - leftcut - (WinWidth MOD 16)) AND $F, aber s.o.!}
- {rightcut := (16 - leftcut - WinWidth) AND $F}
- {das "AND $F" ist wg. evtl. underflow <0}
- NEG BX {BX=-leftcut}
- MOV SI,WinWidth
- MOV AX,16
- ADD AX,BX
- SUB AX,SI
- AND AX,DI {AX = (16 - leftcut - WinWidth) AND $F}
- MOV rightcut,AX
-
- {#_ganzer_ Kacheln im Inneren des Windows je Zeile:}
- {innerTilesX:=(WinWidth - (-rightcut AND $F) - (-leftcut AND $F)) SHR 4;}
- NEG AX
- AND AX,DI
- AND BX,DI
- SUB SI,AX
- SUB SI,BX
- SHR SI,CL
- MOV innerTilesX,SI
-
- {stepX1=Additionsfaktor, um von rechtester (evtl. nur teilweise) sichtbaren}
- { Kachel einer Zeile zur 1. _links nicht geschnittenen_ Kachel der }
- { nächsten Zeile zu kommen}
- {stepX2=dto., aber zur 1. (evtl. nur teilweise) sichtbaren Kachel der }
- { nächsten Zeile}
- {stepX1 := XTiles -(innerTilesX);}
- {stepX2 := stepX1;}
- {IF leftcut<>0 THEN dec(stepX2)} {stepX2 = XTiles -(innerTiles + (leftcut<>0))}
- MOV DX,XTiles
- MOV AX,DX
- SUB AX,SI
- MOV stepX1,AX
- OR BX,BX {für den geg. Bereich gilt: leftcut = 0 <-> -leftcut and $F=0}
- JE @nodec
- DEC AX
- @nodec:
- MOV stepX2,AX
-
-
- {Start-Writeplane links nicht geschnittener Kacheln berechnen:}
- { (WinXMIN - leftcut) AND 3, wird hier berechnet per }
- { (WinXMIN - (leftcut AND $F) AND 3}
- { Dann wird die zugehörige Maske daraus errechnet }
- ADD BX,WinXMIN
- AND BX,3
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- MOV AL,2
- MOV StartWritePlane,AX {muß im Stacksegment liegen!}
-
-
- {nun analog für Y-Richtung:}
- {IF StartVirtualY+WinYMIN-BackY1<0
- THEN KachelnWegOben := (StartVirtualY + WinYMIN - BackY1 - 15) DIV 16
- ELSE KachelnWegOben := (StartVirtualY + WinYMIN - BackY1) DIV 16;}
- MOV AX,StartVirtualY
- ADD AX,WinYMIN
- SUB AX,BackY1
- MOV BX,AX
- SAR AX,CL
- MOV KachelnWegOben,AX
-
- {Index der 1. (evtl. nur teilweise) sichtbaren Kachel berechnen:}
- {actIndex := KachelnWegOben * XTiles + KachelnWegLinks + 1;}
- {Die "+1" ist, da BackTile[]-Zählung bei 0 beginnt, um BackTile[0]}
- {als OffscreenTile freizuhalten!}
- IMUL DX
- ADD AX,KachelnWegLinks
- INC AX
- MOV actIndex,AX
-
- {topcut := (StartVirtualY + WinYMIN - BackY1) AND $F;}
- AND BX,DI
- MOV topcut,BX
-
- {bottomcut := (16 - topcut - WinHeight) AND $F;}
- NEG BX
- MOV SI,WinHeight
- MOV AX,16
- ADD AX,BX
- SUB AX,SI
- AND AX,DI
- MOV bottomcut,AX
-
- {innerTilesY := (WinHeight - (-bottomcut AND $F) - (-topcut AND $F)) SHR 4;}
- NEG AX
- AND AX,DI
- AND BX,DI
- SUB SI,AX
- SUB SI,BX
- SHR SI,CL
- MOV innerTilesY,SI
-
- {---Jetzt zeichnen!---}
-
- { entfällt, da bereits in SetAnimateWindow() gesetzt:
- MOV AX,WinXMIN
- (* MOV x,AX *)
- MOV BX,WinYMIN
- (* MOV y,BX *)
- SHR AX,1
- SHR AX,1
- MOV WinXMINdiv4,AX
- SHL BX,1
- MOV BX,CS:[OFFSET GADR +BX]
- MOV WinYMIN_mul_LINESIZE,BX
- ADD AX,BX
- MOV WinYMINmLINESIZEaWinXMINdiv4,AX
- }
-
- MOV AX,KachelnWegLinks
- MOV xtil,AX
- MOV CX,AX {CX = Kopie von KachelnWegLinks = xtil}
- MOV AX,KachelnWegOben
- MOV ytil,AX
-
- MOV ES,PAGEADR {ein für allemal!}
- MOV BX,leftcut
- {Hier gilt: AX = ytil, BX = Leftcut, CX = xtil, ES = ^Grafiksegment}
- TEST BL,3 {leftcut MOD 4 = 0 ?}
- JZ @useMode1 {ja, Writemode1 nutzbar}
- JMP @useMode0 {nein, Writemode0 verwenden}
-
- @useMode1:
- {Wenn Fensterbreite Vielfaches von 4, leftcut mod 4=0 und linke Fenstergrenze}
- {auf Vielfaches von 4 fällt (dann ist damit auch rightcut mod 4=0) und }
- {durchgehend Writemode1 anwendbar!}
- MOV AX,4105h {Writemode1 einschalten}
- MOV DX,3CEh
- OUT DX,AX
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- MOV DX,3C4h
- OUT DX,AX
-
- CMP topcut,0 {IF ytil ε [0..YTiles( }
- JE @m1SkipTopRow { THEN DX = Yoffscreen := $FFFF }
- MOV AX,ytil { ELSE DX = Yoffscreen := $0000 }
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,WinXMINdiv4 {AX =richtiger Wert, falls gesprungen wird!}
- OR BX,BX {BX=leftcut}
- JZ @m1SkipTopLeftCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,DX { THEN SI := 0 }
- JZ @m1go1 { ELSE SI := actIndex }
- MOV AX,CX {CX = xtil}
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
-
- @m1go1:
- {PROCEDURE DrawUpperLeftTile mit WriteMode1: }
- { in: WinXMIN,WinYMIN = Bildschirmkoordinaten}
- { ES = ^Grafiksegment}
- { SI = Kachelindex }
- { BX = leftcut }
- { CX = xtil }
- { leftcut MOD 4 = 0 }
- { topcut, Win*, SCROLLADR,...}
- {out: ES = ^Grafiksegment}
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {für jede Zeile 4 Bytes}
- SUB CX,SI {CX := 16 - topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erste zu kopierende Tile*zeile*}
-
- MOV AX,BX {BX = leftcut}
- SHR AX,1 {SI um linken cutoff weitersetzen = leftcut DIV 4}
- SHR AX,1
- ADD SI,AX {SI = Zeiger auf erstes zu kopierendes Tile*byte*}
-
- MOV DI,WinYMINmLINESIZEaWinXMINdiv4 {ES:DI = Zieladresse}
- MOV DS,SCROLLADR {DS:SI = Quelladresse}
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16 {BP := (16 - leftcut) DIV 4 = Bytes je Kachelzeile}
- SUB BP,BX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {ist eine Konstante}
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {CX = Zeilenanzahl}
-
- @m1eineZeile4a1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m1eineZeile4a1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {Auf nächste Kachel rechts davon positionieren:}
- INC actIndex
- INC xtil
-
- MOV AX,WinXMIN
- ADD AX,16
- SUB AX,leftcut
- (* MOV x,AX *)
- SHR AX,1
- SHR AX,1
- @m1SkipTopLeftCorner:
- ADD AX,WinYMIN_mul_LINESIZE
- MOV DI,AX {ES:DI = ^Zieladresse}
-
- {Nun innerTilesX nur oben geschnittene Kacheln zeichnen:}
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m1UpperInnerTilesDone
- MOV counter,AX
-
- MOV BX,16 {Korrekturfaktor, um DI eine Kachelzeile hoch und eine}
- SUB BX,topcut {Kachelspalte weiterzusetzen}
- SHL BX,1
- MOV BX,CS:[OFFSET GADR +BX]
- NEG BX
- ADD BX,4 {BX := -(16 - topcut) * LINESIZE + 4}
-
- @m1repeat1:
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m1go2 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go2:
- {PROCEDURE DrawUpperInnerTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { BX = Zeilenkorrektur}
- { leftcut MOD 4 = 0 }
- { topcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel rechts davon}
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt}
- { BX wird nicht verändert}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {für jede Zeile 4 Bytes}
- SUB CX,SI {CX := 16 - topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erste zu kopierende Tile*zeile*}
-
- MOV DX,DS
- MOV DS,SCROLLADR
- MOV AX,LINESIZE-4
-
- @m1eineZeile4b1:
- MOVSB
- MOVSB
- MOVSB
- MOVSB
- ADD DI,AX
- LOOP @m1eineZeile4b1
-
- {DI = ^Start der Zeile unterhalb der Kachel, jetzt auf Start der nächsten}
- {Kachel setzen:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- MOV DS,DX {kein POP BP nötig}
- ADD DI,BX
-
- {Auf nächste Kachel rechts davon positionieren:}
- INC actIndex
- INC xtil
- (* MOV AX,16 *)
- (* ADD x,AX *)
- DEC counter
- JNZ @m1repeat1
-
- @m1UpperInnerTilesDone:
- {ES:DI = ^erste Zeile der rechten oberen Eckkachel}
- CMP rightcut,0
- JE @m1SkipTopRightCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m1go3 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go3:
- {PROCEDURE DrawUpperRightTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { rightcut MOD 4 = 0 }
- { topcut, Win*, SCROLLADR,...}
- {out: ES = ^Grafiksegment }
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {für jede Zeile 4 Bytes}
- SUB CX,SI {CX := 16 - topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erste zu kopierende Tile*zeile*}
-
- MOV AX,rightcut
- MOV DS,SCROLLADR {DS:SI = Quelladresse}
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16 {BP := (16 - rightcut) DIV 4 = Bytes je Kachelzeile}
- SUB BP,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {BX := zu zeichnende Zeilen}
-
- @m1eineZeile4c1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m1eineZeile4c1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m1SkipTopRightCorner:
- {Auf erste linke Kachel positionieren, die oben nicht mehr geschnitten ist:}
- MOV AX,stepx2
- ADD actIndex,AX
- (* MOV AX,WinXMIN *)
- (* MOV x,AX *)
- MOV AX,KachelnWegLinks
- MOV xtil,AX
- INC ytil
-
- @m1SkipTopRow:
- MOV AX,topcut {IF topcut = 0 }
- NEG AX { THEN AX = y := WinYMIN}
- JZ @m1l1 { ELSE AX = y := WinYMIN + (16 - topcut)}
- ADD AX,16
- @m1l1:
- ADD AX,WinYMIN
- (* MOV y,AX *)
-
- MOV DI,AX {DI := y * LINESIZE +X DIV 4}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR +DI]
- ADD DI,WinXMINdiv4
- {ES:DI = ^Zieladresse der 1.Kachel der 1.oben nicht geschnittenen Kachelzeile}
-
- CMP leftcut,0
- JZ @m1SkipLeftColumn
-
- MOV DX,16
- SUB DX,leftcut
- SHR DX,1
- SHR DX,1
- MOV AX,LINESIZE
- SUB AX,DX {Korrekturfaktor für AX}
- MOV LINESIZE_sub_BytesPerPlane,AX
- MOV BytesPerPlane,DX {Bytes zu moven}
-
- MOV AX,innerTilesY
- OR AX,AX
- JBE @m1LeftLoopDone
- MOV counter,AX
-
- PUSH actIndex
- (* PUSH y *)
- PUSH ytil
- PUSH DI
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {ist für Kachelspalte konstant}
- MOV BX,BytesPerPlane
-
- @m1repeat5:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m1go11
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go11:
- {PROCEDURE DrawLeftTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { BX = BytesPerPlane }
- { leftcut MOD 4 = 0 }
- { LINESIZE_sub_BytesPerPlane}
- { leftcutDIV4, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel darunter}
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt }
- { BX wird nicht verändert}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- ADD SI,leftcutDIV4
- MOV AX,LINESIZE_sub_BytesPerPlane
- MOV DX,4
-
- SUB DX,BX
- MOV DS,SCROLLADR
-
- MOV CX,BX {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BX {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {16.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {Nächste Kachel; DI steht schon richtig:}
- MOV AX,XTiles
- ADD actIndex,AX
- (* MOV AX,16 *)
- (* ADD y,AX *)
- INC ytil
-
- DEC counter
- JNZ @m1repeat5
-
- POP DI
- POP ytil
- (* POP y *)
- POP actIndex
-
- @m1LeftLoopDone:
- INC actIndex
- ADD DI,BytesPerPlane
- INC xtil
- (* MOV AX,16 *)
- (* SUB AX,leftcut *)
- (* ADD x,AX *)
-
- @m1SkipLeftColumn:
- {ES:DI = ^Zieladresse der ersten inneren Kachel (immer noch)}
-
- MOV AX,innerTilesY {gibt's überhaupt innere Kacheln?}
- OR AX,AX
- JBE @m1SkipInnerTiles
- CMP innerTilesX,0
- JB @m1SkipInnerTiles
-
- MOV counter,AX
- MOV AX,actIndex {Kopien der aktuellen Werte anlegen}
- MOV tempActIndex,AX
- (* MOV AX,x *)
- (* MOV tempX,AX *)
- MOV AX,xtil
- MOV tempXtil,AX
- (* MOV AX,y *)
- (* MOV tempY,AX *)
- MOV AX,ytil
- MOV tempYtil,AX
- MOV tempDI,DI
-
- CMP rightcut,0
- JE @m1SkipRightColumn
-
- MOV DX,16
- SUB DX,rightcut
- SHR DX,1
- SHR DX,1
- MOV BytesPerPlane,DX
- MOV AX,LINESIZE
- SUB AX,DX
- MOV LINESIZE_sub_BytesPerPlane,AX
-
- MOV AX,innerTilesX
- ADD xtil,AX
- ADD actIndex,AX
- MOV CL,2
- SHL AX,CL
- ADD DI,AX {ES:DI = ^erste rechte Randkachel, die oben nicht geschnitten ist}
- (* SHL AX,CL *)
- (* ADD x,AX *)
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX
- MOV BX,BytesPerPlane
-
- @m1repeat6:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m1go12
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go12:
- {PROCEDURE DrawRightTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { BX = BytesPerPlane }
- { rightcut MOD 4 = 0 }
- { innerTilesY >= 1 }
- { LINESIZE_sub_BytesPerPlane}
- { SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel darunter}
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt }
- { BX wird nicht verändert}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV AX,LINESIZE_sub_BytesPerPlane
- MOV DX,4
-
- SUB DX,BX
- MOV DS,SCROLLADR
-
- MOV CX,BX {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BX {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {16.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {Nächste Kachel; DI steht schon richtig:}
- MOV AX,XTiles
- ADD actIndex,AX
- (* MOV AX,16 *)
- (* ADD y,AX *)
- INC ytil
-
- DEC counter
- JNZ @m1repeat6
-
- MOV DI,tempDI
- MOV AX,tempActIndex
- MOV actIndex,AX
- (* MOV AX,tempX *)
- (* MOV x,tempX *)
- MOV AX,tempXtil
- MOV xtil,AX
- (* MOV AX,tempY *)
- (* MOV y,AX *)
- MOV AX,tempYtil
- MOV ytil,AX
-
- @m1RightLoopDone:
- @m1SkipRightColumn:
- {ES:DI = ^Zieladresse der ersten inneren Kachel (immer noch)}
- {innerTilesX >= 0, innerTilesX >= 1 -> es reichte, innerTilesX=0 zu prüfen:}
-
- CMP innerTilesX,0 {IF (innerTilesX <= 0) OR (innerTilesY <= 0) THEN skip}
- JBE @m1SkipInnerTiles {Falls keine inneren Kachel existieren, dann ist }
- {stattdessen bereits auf erste links nicht ge- }
- {schnittene Kachel der untersten Kachelzeile pos. }
-
-
- {Nun "FOR x:=1 TO innerTilesX DO FOR y:=1 TO innerTilesY DO .." realisieren}
- MOV oldDI,DI {temporäre Kopien von DI und actIndex anlegen}
- MOV BX,actIndex {BX entspricht "oldActIndex"}
-
- MOV AX,innerTilesX
- MOV counter,AX {Zähler für X-Richtung}
- MOV CL,6
-
- @m1xloop:
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {ist für Kachelspalte konstant}
-
- MOV AX,innerTilesY
- MOV CH,AL {CH dient als Zähler für Y-Richtung}
-
-
- @m1yloop:
- MOV SI,BX {SI = temp. actIndex}
- AND SI,Xoffscreen
- JZ @m1go5
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go5:
- {PROCEDURE DrawInnerTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { CL = 6 }
- { SCROLLADR}
- {out: ES:DI = ^Zieladresse der nächsten Kachel darunter}
- { CL = 6}
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt }
- { CH, BX dürfen nicht verändert werden!}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV DX,DS {DS nach DX retten}
- MOV DS,SCROLLADR
-
- MOVSB {1.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4 {ES:DI = ^nächste Kachel}
-
- MOVSB {2.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {3.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {4.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {5.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {6.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {7.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {8.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {9.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {10.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {11.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {12.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {13.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {14.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {15.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {16.Zeile}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
-
- MOV DS,DX
-
- {Nächste Kachel; DI steht schon richtig:}
- ADD BX,XTiles {temp. actIndex in nächste Zeile setzen}
- INC ytil
- (* MOV AX,16 *)
- (* ADD y,AX *)
-
- DEC CH
- JNZ @m1yloop
-
- {actIndex hat noch seinen alten Wert, da nur "oldActIndex" verändert wurde.}
- INC actIndex {actIndex = nächste innere Kachel in oberster Kachelzeile}
- MOV BX,actIndex {und als Startwert für nächste Spalte übernehmen}
-
- MOV DI,oldDI {ES:DI = ^innere Kachel in oberster Kachelzeile}
- ADD DI,4 {eine Kachel weitersetzen}
- MOV oldDI,DI {und als Startwert für nächste Spalte übernehmen}
-
- MOV AX,tempYtil
- MOV ytil,AX {Y-Koordinate wieder auf oberste innere Kachelzeile setzen}
- (* MOV AX,oldY *)
- (* MOV y,AX *)
-
- INC xtil {X-Koordinate eine Kachelspalte weitersetzen}
- (* MOV AX,16 *)
- (* ADD x,AX *)
-
- DEC counter
- JNZ @m1xloop
-
- MOV DI,tempDI {Damit: ES:DI, actIndex, xtil, ytil, x, y zeigen wieder}
- MOV AX,tempActIndex {auf die erste, innere Kachel (N.B.: y, ytil wurden }
- MOV actIndex,AX {bereits weiter oben wiederhergestellt)}
- MOV AX,tempXtil
- MOV xtil,AX
- (* MOV AX,tempX *)
- (* MOV x,AX *)
-
- MOV AX,innerTilesY
- MOV DX,AX {Kopie in DX aufheben}
- ADD ytil,AX {ytil zeigt jetzt auf unterste Kachelzeile}
-
- MOV CL,5
- SHL AX,CL {dto. für DI: inc(DI,16 * innerTilesY * LINESIZE) }
- MOV BX,AX
- ADD DI,CS:[OFFSET GADR +BX]
- (* SHR AX,1 *)
- (* ADD y,AX *) {dto. für y: inc(y,16 * innerTilesY) }
-
- MOV AX,XTiles
- MUL DX {AX := XTiles * innerTilesY}
- ADD actIndex,AX {dto. für actIndex: inc(actIndex,XTiles * innerTilesY) }
-
- @m1SkipInnerTiles:
- {ES:DI, actIndex, xtil, ytil, x, y zeigen auf erste innere Kachel der}
- {untersten Kachelzeile}
- CMP bottomcut,0
- JE @m1fertig
-
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m1LowerInnerTilesDone {stehen wir bereits auf rechter unterer Eckkachel?}
- MOV counter,AX
-
- {Additionsfaktor berechnen, um von unten nach oben zu kommen:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- {BX := -(16 - bottomcut) * LINESIZE + 4}
- MOV BX,16
- SUB BX,bottomcut
- SHL BX,1
- MOV BX,CS:[OFFSET GADR +BX]
- NEG BX
- ADD BX,4
-
- @m1repeat4:
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m1go8
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go8:
- {PROCEDURE DrawLowerInnerTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { BX = Korrekturfaktor für Zeilenadressen }
- { bottomcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel rechts davon}
- { BX = Korrekturfaktor für Zeilenadressen }
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt}
- { DX wird nicht benutzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV AX,DS {DS nach AX retten}
- MOV DS,SCROLLADR
-
- @m1eineZeile4e1:
- MOVSB
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
- LOOP @m1eineZeile4e1
-
- MOV DS,AX
-
- {DI = ^Start der Zeile unterhalb der Kachel, jetzt auf Start der nächsten}
- {Kachel setzen:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- ADD DI,BX
-
- {Auf nächste Kachel rechts davon positionieren:}
- INC actIndex
- INC xtil
- (* MOV AX,16 *)
- (* ADD x,AX *)
-
- DEC counter
- JNZ @m1repeat4
-
- @m1LowerInnerTilesDone:
- {ES:DI, actIndex, xtil, ytil, x, y zeigen auf untere rechte Eckkachel}
- CMP rightcut,0
- JE @m1SkipLowerRightCorner
-
- PUSH DI
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m1go9
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go9:
- {PROCEDURE DrawLowerRightTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { rightcut MOD 4 = 0 }
- { rightcut, bottomcut, Win*, SCROLLADR,...}
- {out: ES = ^Grafiksegment }
- {rem: WriteMode1 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
- MOV BX,16
- SUB BX,rightcut
- SHR BX,1
- SHR BX,1 {BX = BytesPerPlane = (16 - rightcut) DIV 4}
-
- MOV DS,SCROLLADR
-
- MOV AX,LINESIZE
- SUB AX,BX
- MOV DX,4
- SUB DX,BX
- PUSH BP
- MOV BP,CX {BP=Zeilenzähler}
-
- @m1eineZeile4g1:
- MOV CX,BX
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BP
- JNZ @m1eineZeile4g1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- POP DI {ES:DI etc. zeigen auf rechte untere Eckkachel}
-
- @m1SkipLowerRightCorner:
- CMP leftcut,0
- JE @m1fertig
-
- {jetzt auf linke untere Eckkachel positionieren:}
- MOV AX,innerTilesX
- INC AX
- SUB actIndex,AX {dec(actIndex,innerTilesX + 1) }
- SUB xtil,AX {dec(xtil,innerTilesX + 1) }
- MOV CL,2
- SHL AX,CL
- SUB DI,AX {dec(DI,4 * (innerTilesX + 1) }
- ADD DI,leftcutDIV4 {berücksichtige: Eckkachel kann links geschnitten sein}
- (* MOV AX,WinXMIN *)
- (* MOV x,AX *)
-
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m1go7
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go7:
- {PROCEDURE DrawLowerLeftTile mit WriteMode1: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { rightcut MOD 4 = 0 }
- { leftcut, bottomcut, Win*, SCROLLADR,...}
- {out: (ES = ^Grafiksegment) }
- {rem: WriteMode1 ist bereits gesetzt (und bleibt gesetzt)}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV AX,leftcut
- MOV BX,AX
- MOV CL,2
- SHR AX,CL
- ADD SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV DS,SCROLLADR
-
- PUSH BP
- MOV BP,16
- SUB BP,BX
- SHR BP,1
- SHR BP,1 {BP:=(16 - leftcut) DIV 4}
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV BX,CX {BX = Zeilenzähler}
-
- @m1eineZeile4d1:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BX
- JNZ @m1eineZeile4d1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m1fertig:
- {Jetzt wieder auf WriteMode0 zurückschalten:}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- JMP @Sprites_zeichnen
-
- {----------------------------------------------------}
-
- @useMode0:
- CMP topcut,0 {IF ytil ε [0..YTiles( }
- JE @m0SkipTopRow { THEN DX = Yoffscreen := $FFFF }
- MOV AX,ytil { ELSE DX = Yoffscreen := $0000 }
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,WinXMINdiv4 {AX = richtiger Wert, falls gesprungen wird!}
- OR BX,BX {BX=leftcut}
- JZ @m0SkipTopLeftCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,DX { THEN SI := 0 }
- JZ @m0go1 { ELSE SI := actIndex }
- MOV AX,CX {CX = xtil}
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
-
- @m0go1:
- {PROCEDURE DrawUpperLeftTile mit WriteMode0: }
- { in: WinXMIN,WinYMIN = Bildschirmkoordinaten}
- { ES = ^Grafiksegment}
- { SI = Kachelindex }
- { BX = leftcut }
- { CX = xtil }
- { topcut, Win*, SCROLLADR,...}
- {out: ES = ^Grafiksegment}
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {für jede Zeile 4 Bytes}
- SUB CX,SI {CX := 16 - topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erste zu kopierende Tile*zeile*}
-
- MOV AX,BX {BX = leftcut}
- SHR AX,1 {SI um linken cutoff weitersetzen = leftcut DIV 4}
- SHR AX,1
- ADD SI,AX {SI = Zeiger auf erstes zu kopierendes Tile*byte*}
-
- MOV DI,WinYMINmLINESIZEaWinXMINdiv4 {ES:DI = Zieladresse}
- MOV DS,SCROLLADR {DS:SI = Quelladresse}
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3 {BP:=(16 + 3 - leftcut) DIV 4 = Bytes je Kachelzeile}
- SUB BP,BX
- PUSH BP {BP für nächste Plane merken}
- SHR BP,1
- SHR BP,1
-
- MOV AH,BL {BL = leftcut}
- AND AH,3
- MOV AL,4
- MOV DX,3CEh
- OUT DX,AX {erste Leseplane wählen}
- PUSH AX
- MOV DX,3C4h
- MOV AX,0102h
- OUT DX,AX {Schreibplane 0 wählen}
-
- MOV AX,LINESIZE {ist eine Konstante}
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {CX = Zeilenanzahl}
-
- PUSH SI
- PUSH DI
- PUSH BX
- @m0eineZeile4a1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a1
- POP BX
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0202h
- OUT DX,AX {Schreibplane 1 wählen}
- MOV DX,3CEh
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap1a
- INC SI
- @nowrap1a:
- OUT DX,AX {nächste Leseplane wählen}
- POP BP {BP = 16 + 3 - leftcut }
- DEC BP
- PUSH BP
- PUSH AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {ist eine Konstante}
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- PUSH BX
- @m0eineZeile4a2:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a2
- POP BX
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0402h
- OUT DX,AX {Schreibplane 2 wählen}
- MOV DX,3CEh
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap2a
- INC SI
- @nowrap2a:
- OUT DX,AX {nächste Leseplane wählen}
- POP BP {BP = 16 + 2 - leftcut }
- DEC BP
- PUSH BP
- PUSH AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {ist eine Konstante}
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- PUSH BX
- @m0eineZeile4a3:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a3
- POP BX
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0802h
- OUT DX,AX {Schreibplane 3 wählen}
- MOV DX,3CEh
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap3a
- INC SI
- @nowrap3a:
- OUT DX,AX {nächste Leseplane wählen}
- POP BP {BP = 16+ 1 - leftcut }
- DEC BP
-
-
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {ist eine Konstante}
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- @m0eineZeile4a4:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a4
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {Auf nächste Kachel rechts davon positionieren:}
- INC actIndex
- INC xtil
-
- MOV AX,WinXMIN
- ADD AX,16
- SUB AX,leftcut
- (* MOV x,AX *)
- SHR AX,1
- SHR AX,1
- @m0SkipTopLeftCorner:
- ADD AX,WinYMIN_mul_LINESIZE
- MOV DI,AX {ES:DI = ^Zieladresse}
-
- {Nun innerTilesX nur oben geschnittene Kacheln zeichnen:}
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m0UpperInnerTilesDone
- MOV counter,AX
-
- MOV BX,16 {Korrekturfaktor, um DI einer Kachelzeile hoch und eine}
- SUB BX,topcut {Kachelspalte weiterzusetzen}
- SHL BX,1
- MOV AX,CS:[OFFSET GADR +BX]
- NEG AX
- ADD AX,4
- MOV Korrektur,AX {Korrektur := -(16 - topcut) * LINESIZE + 4}
-
- @m0repeat1:
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m0go2 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go2:
- {PROCEDURE DrawUpperInnerTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { topcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel rechts davon}
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {für jede Zeile 4 Bytes}
- SUB CX,SI {CX := 16 - topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erste zu kopierende Tile*zeile*}
-
- PUSH BP {BP retten}
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX {erste Schreibplane wählen}
- PUSH AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX {Leseplane 0 wählen}
-
- MOV DS,SCROLLADR {jetzt frei: AX, BX, BP, DX}
-
- MOV BX,CX {Zeilenzählerkopie}
- MOV BP,SI {BP = Kopie von SI}
- MOV AX,DI {AX = Kopie von DI}
- @m0eineZeile4b1:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b1
- MOV SI,BP {alte Werte wiederherstellen}
- MOV DI,AX
- MOV CX,BX
-
- MOV AX,0104h
- OUT DX,AX {DX = 3CEh -> Leseplane 1 wählen}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1b
- MOV AH,1
- INC DI
- @nowrap1b:
- OUT DX,AX {nächste Schreibplane wählen}
- PUSH AX
- MOV AX,DI
-
- @m0eineZeile4b2:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b2
- MOV SI,BP {alte Werte wiederherstellen}
- MOV DI,AX
- MOV CX,BX
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2b
- MOV AH,1
- INC DI
- @nowrap2b:
- OUT DX,AX {DX = 3C4h -> nächste Schreibplane wählen}
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX {Leseplane 2 wählen}
- MOV AX,DI
-
- @m0eineZeile4b3:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b3
- MOV SI,BP {alte Werte wiederherstellen}
- MOV DI,AX
- MOV CX,BX
-
- MOV AX,0304h
- OUT DX,AX {DX = 3CEh -> Leseplane 3 wählen}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3b
- MOV AH,1
- INC DI
- @nowrap3b:
- OUT DX,AX {letzte Schreibplane wählen: keine PUSHs mehr}
-
- @m0eineZeile4b4:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b4
- {alte Werte nicht wiederherstellen}
-
- POP BP {TP zufriedenstellen}
- MOV AX,SEG @Data
- MOV DS,AX
-
- {DI = ^Start der Zeile unterhalb der Kachel, jetzt auf Start der nächsten}
- {Kachel setzen:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- ADD DI,Korrektur
- {-1, weil exakt einmal "inc di" ausgeführt wurde!}
- DEC DI
-
- {Auf nächste Kachel rechts davon positionieren:}
- INC actIndex
- INC xtil
- (* MOV AX,16 *)
- (* ADD x,AX *)
- DEC counter
- JNZ @m0repeat1
-
- @m0UpperInnerTilesDone:
- {ES:DI = ^erste Zeile der rechten oberen Eckkachel}
- CMP rightcut,0
- JE @m0SkipTopRightCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m0go3 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go3:
- {PROCEDURE DrawUpperRightTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { StartWritePlane = erste zu beschreibende Bitplane}
- { topcut, rightcut, Win*, SCROLLADR,...}
- {out: ES = ^Grafiksegment }
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {für jede Zeile 4 Bytes}
- SUB CX,SI {CX := 16 - topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erste zu kopierende Tile*zeile*}
-
- MOV BX,rightcut
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV DS,SCROLLADR {DS:SI = Quelladresse}
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- MOV BP,16+3 {BP:=(16 + 3 - rightcut) DIV 4 = Bytes je Kachelzeile}
- SUB BP,BX
- PUSH BP
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {BX := zu zeichnende Zeilen}
-
- PUSH BX
- PUSH SI
- PUSH DI
- @m0eineZeile4c1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c1
- POP DI
- POP SI
- POP BX
- POP BP
- POP AX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap1c
- MOV AH,1
- INC DI
- @nowrap1c:
- MOV DX,3C4h
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
-
- DEC BP {BP := 16 + 2 - rightcut}
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH BX
- PUSH SI
- PUSH DI
- @m0eineZeile4c2:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c2
- POP DI
- POP SI
- POP BX
- POP BP
- POP AX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap2c
- MOV AH,1
- INC DI
- @nowrap2c:
- MOV DX,3C4h
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
-
- DEC BP {BP := 16 + 1 - rightcut}
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH BX
- PUSH SI
- PUSH DI
- @m0eineZeile4c3:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c3
- POP DI
- POP SI
- POP BX
- POP BP
- POP AX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap3c
- MOV AH,1
- INC DI
- @nowrap3c:
- MOV DX,3C4h
- OUT DX,AX
-
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
-
- DEC BP {BP := 16 + 0 - rightcut}
-
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- @m0eineZeile4c4:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c4
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m0SkipTopRightCorner:
- {Auf erste linke Kachel positionieren, die oben nicht mehr geschnitten ist:}
- MOV AX,stepx2
- ADD actIndex,AX
- (* MOV AX,WinXMIN *)
- (* MOV x,AX *)
- MOV AX,KachelnWegLinks
- MOV xtil,AX
- INC ytil
-
- @m0SkipTopRow:
- MOV AX,topcut {IF topcut = 0 }
- NEG AX { THEN AX = y := WinYMIN}
- JZ @m0l1 { ELSE AX = y := WinYMIN + (16 - topcut)}
- ADD AX,16
- @m0l1:
- ADD AX,WinYMIN
- (* MOV y,AX *)
-
- MOV DI,AX {DI := y * LINESIZE +X DIV 4}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR +DI]
- ADD DI,WinXMINdiv4
- {ES:DI = ^Zieladresse der 1.Kachel der 1.oben nicht geschnittenen Kachelzeile}
-
- CMP leftcut,0
- JZ @m0SkipLeftColumn
-
- MOV DX,16+3
- SUB DX,leftcut
- SHR DX,1
- SHR DX,1
- MOV AX,LINESIZE
- SUB AX,DX {Korrekturfaktor für AX}
- MOV LINESIZE_sub_BytesPerPlane,AX
- MOV BytesPerPlane,DX {Bytes zu moven}
-
- MOV AX,innerTilesY
- OR AX,AX
- JBE @m0LeftLoopDone
- MOV counter,AX
-
- PUSH actIndex
- (* PUSH y *)
- PUSH ytil
- PUSH DI
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {ist für Kachelspalte konstant}
-
- @m0repeat5:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m0go11
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go11:
- {PROCEDURE DrawLeftTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { StartLesePlane = erste Bitplane, von der gelesen wird}
- { LINESIZE_sub_BytesPerPlane, BytesPerPlane = Korrekturfaktoren}
- { leftcut, leftcutDIV4, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel darunter}
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- PUSH BP
- ADD SI,leftcutDIV4
- MOV DX,3C4h
- MOV AX,0102h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,StartLesePlane
- OUT DX,AX
- MOV BX,AX
-
- MOV AX,16+3
- SUB AX,leftcut
- PUSH AX
- SHR AX,1
- SHR AX,1
- MOV BP,AX
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV DS,SCROLLADR
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- INC BH
- AND BH,3
- JNE @nowrap11a
- INC SI
- @nowrap11a:
- MOV AX,BX
- MOV DX,3CEh
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,0202h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- INC BH
- AND BH,3
- JNE @nowrap11b
- INC SI
- @nowrap11b:
- MOV AX,BX
- MOV DX,3CEh
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,0402h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- INC BH
- AND BH,3
- JNE @nowrap11c
- INC SI
- @nowrap11c:
- MOV AX,BX
- MOV DX,3CEh
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,0802h
- OUT DX,AX
-
- DEC BP
-
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
-
-
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {Nächste Kachel; DI steht schon richtig:}
- MOV AX,XTiles
- ADD actIndex,AX
- (* MOV AX,16 *)
- (* ADD y,AX *)
- INC ytil
-
- DEC counter
- JNZ @m0repeat5
-
- POP DI
- POP ytil
- (* POP y *)
- POP actIndex
-
- @m0LeftLoopDone:
- INC actIndex
- ADD DI,BytesPerPlane
-
- {-1, weil exakt einmal "inc di" ausgeführt wurde!}
- DEC DI
-
- INC xtil
- (* MOV AX,16 *)
- (* SUB AX,leftcut *)
- (* ADD x,AX *)
-
- @m0SkipLeftColumn:
- {ES:DI = ^Zieladresse der ersten inneren Kachel (immer noch)}
-
- MOV AX,innerTilesY {gibt's überhaupt innere Kacheln?}
- OR AX,AX
- JBE @m0SkipInnerTiles {nein}
- CMP innerTilesX,0
- JB @m0SkipInnerTiles
-
- MOV counter,AX
- MOV AX,actIndex {Kopien der aktuellen Werte anlegen}
- MOV tempActIndex,AX
- (* MOV AX,x *)
- (* MOV tempX,AX *)
- MOV AX,xtil
- MOV tempXtil,AX
- (* MOV AX,y *)
- (* MOV tempY,AX *)
- MOV AX,ytil
- MOV tempYtil,AX
- MOV tempDI,DI
-
- CMP rightcut,0
- JE @m0SkipRightColumn
-
- MOV DX,16
- SUB DX,rightcut
- SHR DX,1
- SHR DX,1
- MOV BytesPerPlane,DX
- MOV AX,LINESIZE
- SUB AX,DX
- MOV LINESIZE_sub_BytesPerPlane,AX
-
- MOV AX,innerTilesX
- ADD xtil,AX
- ADD actIndex,AX
- MOV CL,2
- SHL AX,CL
- ADD DI,AX {ES:DI = ^erste rechte Randkachel, die oben nicht geschnitten}
- (* SHL AX,CL *)
- (* ADD x,AX *)
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX
-
- @m0repeat6:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m0go12
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go12:
- {PROCEDURE DrawRightTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { StartWritePlane = erste zu beschreibende Bitplane}
- { innerTilesY >= 1 }
- { rightcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel darunter}
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- PUSH BP
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
- MOV BX,AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
-
- MOV AX,16+3
- SUB AX,rightcut
- PUSH AX
- SHR AX,1
- SHR AX,1
- MOV BP,AX
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV DS,SCROLLADR
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- SHL BH,1
- CMP BH,16
- JNE @nowrap12a
- MOV BH,1
- INC DI
- @nowrap12a:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- SHL BH,1
- CMP BH,16
- JNE @nowrap12b
- MOV BH,1
- INC DI
- @nowrap12b:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- SHL BH,1
- CMP BH,16
- JNE @nowrap12c
- MOV BH,1
- INC DI
- @nowrap12c:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
-
- DEC BP
-
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
-
-
- MOV CX,BP {1.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^nächste Kachel}
-
- MOV CX,BP {2.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.Zeile}
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- DEC DI
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {Nächste Kachel; DI steht schon richtig:}
- MOV AX,XTiles
- ADD actIndex,AX
- (* MOV AX,16 *)
- (* ADD y,AX *)
- INC ytil
-
- DEC counter
- JNZ @m0repeat6
-
- MOV DI,tempDI
- MOV AX,tempActIndex
- MOV actIndex,AX
- (* MOV AX,tempX *)
- (* MOV x,tempX *)
- MOV AX,tempXtil
- MOV xtil,AX
- (* MOV AX,tempY *)
- (* MOV y,AX *)
- MOV AX,tempYtil
- MOV ytil,AX
-
- @m0RightLoopDone:
- @m0SkipRightColumn:
- {ES:DI = ^Zieladresse der ersten inneren Kachel (immer noch)}
- {innerTilesX >= 0, innerTilesX >= 1 -> es reichte, innerTilesX=0 zu prüfen:}
-
- CMP innerTilesX,0 {IF (innerTilesX <= 0) OR (innerTilesY <= 0) THEN skip}
- JBE @m0SkipInnerTiles {Falls keine inneren Kachel existieren, dann ist }
- {stattdessen bereits auf erste links nicht ge- }
- {schnittene Kachel der untersten Kachelzeile pos. }
-
-
- {Nun "FOR x:=1 TO innerTilesX DO FOR y:=1 TO innerTilesY DO .." realisieren}
- MOV oldDI,DI {temporäre Kopien von DI und actIndex anlegen}
- MOV AX,actIndex
- MOV oldActIndex,AX
-
- MOV AX,innerTilesX
- MOV counter,AX {Zähler für X-Richtung}
- MOV CL,6
-
- @m0xloop:
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {ist für Kachelspalte konstant}
-
- MOV AX,innerTilesY
- MOV CH,AL {CH dient als Zähler für Y-Richtung}
-
-
- @m0yloop:
- MOV SI,oldActIndex {SI = temp. actIndex}
- AND SI,Xoffscreen
- JZ @m0go5
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go5:
- {PROCEDURE DrawInnerTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { CL = 6 }
- { SCROLLADR}
- {out: ES:DI = ^Zieladresse der nächsten Kachel darunter}
- { CL = 6}
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt }
- { CH wird nicht verändert!}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV DS,SCROLLADR
-
- MOV DX,3C4h
- MOV AX,StartWritePlane
- MOV BX,AX
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
-
- MOVSW {1.Zeile}
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^nächste Kachel}
-
- MOVSW {2.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.Zeile}
- MOVSW
-
- SUB SI,16*4
- SUB DI,15*LINESIZE +4
-
- MOV AX,0104h
- OUT DX,AX {DX = 3CEh}
- SHL BH,1
- CMP BH,16
- JNE @nowrap5a
- MOV BH,1
- INC DI
- @nowrap5a:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
-
- MOVSW {1.Zeile}
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^nächste Kachel}
-
- MOVSW {2.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.Zeile}
- MOVSW
-
- SUB SI,16*4
- SUB DI,15*LINESIZE +4
-
- SHL BH,1
- CMP BH,16
- JNE @nowrap5b
- MOV BH,1
- INC DI
- @nowrap5b:
- MOV AX,BX
- OUT DX,AX {DX = 3C4h}
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
-
- MOVSW {1.Zeile}
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^nächste Kachel}
-
- MOVSW {2.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.Zeile}
- MOVSW
-
- SUB SI,16*4
- SUB DI,15*LINESIZE +4
-
- MOV AX,0304h
- OUT DX,AX {DX = 3CEh}
- SHL BH,1
- CMP BH,16
- JNE @nowrap5c
- MOV BH,1
- INC DI
- @nowrap5c:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
-
- MOVSW {1.Zeile}
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^nächste Kachel}
-
- MOVSW {2.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.Zeile}
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.Zeile}
- MOVSW
-
-
- MOV AX,SEG @Data
- MOV DS,AX
-
- ADD DI,LINESIZE-4-1
-
- {Nächste Kachel; DI steht schon richtig:}
- MOV AX,XTiles {temp. actIndex in nächste Zeile setzen}
- ADD oldActIndex,AX
- INC ytil
- (* MOV AX,16 *)
- (* ADD y,AX *)
-
- DEC CH
- JNZ @m0yloop
-
- {actIndex hat noch seinen alten Wert, da nur oldActIndex verändert wurde.}
- INC actIndex {actIndex = nächste innere Kachel in oberster Kachelzeile}
- MOV AX,actIndex {und als Startwert für nächste Spalte übernehmen}
- MOV oldActIndex,AX
-
- MOV DI,oldDI {ES:DI = ^innere Kachel in oberster Kachelzeile}
- ADD DI,4 {eine Kachel weitersetzen}
- MOV oldDI,DI {und als Startwert für nächste Spalte übernehmen}
-
- MOV AX,tempYtil
- MOV ytil,AX {Y-Koordinate wieder auf oberste innere Kachelzeile setzen}
- (* MOV AX,oldY *)
- (* MOV y,AX *)
-
- INC xtil {X-Koordinate eine Kachelspalte weitersetzen}
- (* MOV AX,16 *)
- (* ADD x,AX *)
-
- DEC counter
- JNZ @m0xloop
-
- MOV DI,tempDI {Damit: ES:DI, actIndex, xtil, ytil, x, y zeigen wieder}
- MOV AX,tempActIndex {auf die erste, innere Kachel (N.B.: y, ytil wurden }
- MOV actIndex,AX {bereits weiter oben wiederhergestellt)}
- MOV AX,tempXtil
- MOV xtil,AX
- (* MOV AX,tempX *)
- (* MOV x,AX *)
-
- MOV AX,innerTilesY
- MOV DX,AX {Kopie in DX aufheben}
- ADD ytil,AX {ytil zeigt jetzt auf unterste Kachelzeile}
-
- MOV CL,5
- SHL AX,CL {dto. für DI: inc(DI,16 * innerTilesY * LINESIZE) }
- MOV BX,AX
- ADD DI,CS:[OFFSET GADR +BX]
- (* SHR AX,1 *)
- (* ADD y,AX *) {dto. für y: inc(y,16 * innerTilesY) }
-
- MOV AX,XTiles
- MUL DX {AX := XTiles * innerTilesY}
- ADD actIndex,AX {dto. für actIndex: inc(actIndex,XTiles * innerTilesY) }
-
- @m0SkipInnerTiles:
- {ES:DI, actIndex, xtil, ytil, x, y zeigen auf erste innere Kachel der}
- {untersten Kachelzeile}
- CMP bottomcut,0
- JE @m0fertig
-
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m0LowerInnerTilesDone {stehen wir bereits auf rechter unterer Eckkachel?}
- MOV counter,AX
-
- {Additionsfaktor berechnen, um von unten nach oben zu kommen:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- {Korrektur:=-(16 - bottomcut) * LINESIZE + 4}
- MOV BX,16
- SUB BX,bottomcut
- SHL BX,1
- MOV AX,CS:[OFFSET GADR +BX]
- NEG AX
- ADD AX,4-1 {-1, weil durch Planing DI 1x erhöht wird}
- MOV Korrektur,AX
-
- @m0repeat4:
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m0go8
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go8:
- {PROCEDURE DrawLowerInnerTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { bottomcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^Zieladresse der nächsten Kachel rechts davon}
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt}
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
-
- MOV DS,SCROLLADR
-
- MOV BX,CX
- PUSH SI
- PUSH DI
- @m0eineZeile4e1:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e1
- POP DI
- POP SI
- MOV CX,BX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap8a
- MOV AH,1
- INC DI
- @nowrap8a:
- MOV DX,3C4h
- OUT DX,AX
- MOV BX,AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
-
- MOV AX,CX
- PUSH SI
- PUSH DI
- @m0eineZeile4e2:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e2
- POP DI
- POP SI
- MOV CX,AX
-
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
- SHL BH,1
- CMP BH,16
- JNE @nowrap8b
- MOV BH,1
- INC DI
- @nowrap8b:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
-
- MOV BX,CX
- PUSH SI
- PUSH DI
- @m0eineZeile4e3:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e3
- POP DI
- POP SI
- MOV CX,BX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap8c
- MOV AH,1
- INC DI
- @nowrap8c:
- MOV DX,3C4h
- OUT DX,AX
- MOV BX,AX
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
-
- @m0eineZeile4e4:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e4
-
-
- MOV AX,SEG @Data
- MOV DS,AX
-
- {DI = ^Start der Zeile unterhalb der Kachel, jetzt auf Start der nächsten}
- {Kachel setzen:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- ADD DI,Korrektur
-
- {Auf nächste Kachel rechts davon positionieren:}
- INC actIndex
- INC xtil
- (* MOV AX,16 *)
- (* ADD x,AX *)
-
- DEC counter
- JNZ @m0repeat4
-
- @m0LowerInnerTilesDone:
- {ES:DI, actIndex, xtil, ytil, x, y zeigen auf untere rechte Eckkachel}
- CMP rightcut,0
- JE @m0SkipLowerRightCorner
-
- PUSH DI
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m0go9
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go9:
- {PROCEDURE DrawLowerRightTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { StartWritePlane = erste zu beschreibende Bitplane}
- { rightcut MOD 4 = 0 }
- { rightcut, bottomcut, Win*, SCROLLADR,...}
- {out: ES = ^Grafiksegment }
- {rem: WriteMode0 ist bereits gesetzt und bleibt gesetzt}
- PUSH BP
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
- MOV BX,16+3
- SUB BX,rightcut
- PUSH BX
- SHR BX,1
- SHR BX,1 {BX = BytesPerPlane = (16 + 3 - rightcut) DIV 4}
-
- MOV DS,SCROLLADR
-
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
-
- MOV AX,LINESIZE
- SUB AX,BX
- MOV DX,4
- SUB DX,BX
- MOV BP,BX {BP = Bytes je Zeile}
- MOV BL,CL {BL = Zeilenzähler }
- MOV BH,CL {Kopie nach BH}
-
- PUSH SI
- PUSH DI
- @m0eineZeile4g1:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g1
- POP DI
- POP SI
- MOV BL,BH
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap9a
- MOV AH,1
- INC DI
- @nowrap9a:
- MOV DX,3C4h
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- @m0eineZeile4g2:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g2
- POP DI
- POP SI
- MOV BL,BH
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap9b
- MOV AH,1
- INC DI
- @nowrap9b:
- MOV DX,3C4h
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- @m0eineZeile4g3:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g3
- POP DI
- POP SI
- MOV BL,BH
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap9c
- MOV AH,1
- INC DI
- @nowrap9c:
- MOV DX,3C4h
- OUT DX,AX
- POP BP
- DEC BP
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- @m0eineZeile4g4:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g4
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- POP DI {ES:DI etc. zeigen auf rechte untere Eckkachel}
-
- @m0SkipLowerRightCorner:
- CMP leftcut,0
- JE @m0fertig
-
- {jetzt auf linke untere Eckkachel positionieren:}
- MOV AX,innerTilesX
- INC AX
- SUB actIndex,AX {dec(actIndex,innerTilesX + 1) }
- SUB xtil,AX {dec(xtil,innerTilesX + 1) }
- MOV CL,2
- SHL AX,CL
- SUB DI,AX {dec(DI,4 * (innerTilesX + 1) }
- ADD DI,leftcutDIV4 {berücksichtige: Eckkachel kann links geschnitten sein}
- INC DI
- (* MOV AX,WinXMIN *)
- (* MOV x,AX *)
-
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m0go7
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go7:
- {PROCEDURE DrawLowerLeftTile mit WriteMode0: }
- { in: ES:DI = ^Zieladresse}
- { SI = Kachelindex }
- { StartLesePlane = erste Bitplane, von der gelesen wird}
- { rightcut MOD 4 = 0 }
- { leftcut, bottomcut, Win*, SCROLLADR,...}
- {out: (ES = ^Grafiksegment) }
- {rem: WriteMode0 ist bereits gesetzt (und bleibt gesetzt)}
- PUSH BP
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {Offsetadresse der Kachel berechnen:}
- MOV CL,6 {jede Kachel ist 64 Bytes lang, also}
- SHL AX,CL {AX := Kachel * 64 = Kachel SHL 6 }
- MOV SI,AX
-
- MOV AX,leftcut
- MOV BX,AX
- MOV CL,2
- SHR AX,CL
- ADD SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV DS,SCROLLADR
-
- MOV DX,3C4h
- MOV AX,0102h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,StartLesePlane
- OUT DX,AX
-
- MOV BP,16+3
- SUB BP,BX
- PUSH BP
- PUSH AX
- SHR BP,1
- SHR BP,1 {BP := (16 + 3 - leftcut) DIV 4}
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV BL,CL {BL=Zeilenzähler}
- MOV BH,CL {Kopie davon}
-
- PUSH SI
- PUSH DI
- @m0eineZeile4d1:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d1
- POP DI
- POP SI
-
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap7a
- INC SI
- @nowrap7a:
- MOV DX,3CEh
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3C4h
- MOV AX,0202h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BL,BH
-
- PUSH SI
- PUSH DI
- @m0eineZeile4d2:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d2
- POP DI
- POP SI
-
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap7b
- INC SI
- @nowrap7b:
- MOV DX,3CEh
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3C4h
- MOV AX,0402h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BL,BH
-
- PUSH SI
- PUSH DI
- @m0eineZeile4d3:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d3
- POP DI
- POP SI
-
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap7c
- INC SI
- @nowrap7c:
- MOV DX,3CEh
- OUT DX,AX
- POP BP
- DEC BP
- MOV DX,3C4h
- MOV AX,0802h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BL,BH
-
- @m0eineZeile4d4:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d4
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m0fertig:
-
-
- {------- ab hier: Sprites auf aktuelle Grafikseite bringen}
-
- @Sprites_zeichnen:
- MOV SI,NMAX*2
- PUSH BP {BP nachher wieder poppen!}
-
-
- @zeichne:
- CMP SI,SplitIndex_mal2 {Splitpunkt?}
- JNE @SZeich
-
- MOV AX,WinXMIN
- {ja: Win* Werte auf gesamte Fläche (0,0)..(XMAX,YMAX) setzen:}
- OR AX,WinYMIN
- JNZ @replace1
- CMP WinXMAX,XMAX
- JNE @replace2
- CMP WinYMAX,YMAX
- JE @replacedone
- JMP @replace3 {short}
-
- @replace1:
- MOV WinXMIN,0
- MOV WinYMIN,0
- MOV WinXMINdiv4,0
- MOV WinYMIN_mul_LINESIZE,0
- MOV WinYMINmLINESIZEaWinXMINdiv4,0
- @replace2:
- MOV WinXMAX,XMAX
- MOV WinWidth,XMAX+1
- MOV WinWidthDiv4,(XMAX+1)/4
- @replace3:
- MOV WinYMAX,YMAX
- MOV WinHeight,YMAX+1
- MOV WinLowerRight,0
- @replacedone:
-
- {DS = normales Datensegment, ES = Grafikseitensegment, }
- {SI = Spritepositionsnummer * 2 }
- @SZeich:
- MOV BX,[SI + OFFSET SpriteN] {BX = SpriteN[?] = Spriteladenummer}
- SHL BX,1 {BX = Spriteladenummer * 2}
-
- {Jetzt: "SpriteN[?] := SpriteN[NextSprite[?]]" berechnen:}
- MOV BX,[BX + OFFSET NextSprite] {AX = NextSprite[SpriteN[?]]}
- MOV [SI + OFFSET SpriteN],BX {als neue SpriteN[?] übernehmen}
- SHL BX,1
-
-
- JNZ @aktiv
- JMP @noSprite
-
-
- @aktiv:
- PUSH SI {Spritepositionsnummer * 2 retten}
-
- MOV DX,[SI + OFFSET SpriteX] {if SpriteX > xmax then skip_sprite}
- SUB DX,StartVirtualX {virtuelle -> absolute Koordinaten }
- MOV AX,WinXMAX
- CMP DX,AX
- JLE @L0
- @ToSprite_fertig: {Sprungleiste zu @Sprite_fertig}
- JMP @Sprite_fertig
- @L0:
- MOV CS:WORD PTR @akt_SpriteX+1,DX
- MOV DI,[SI + OFFSET SpriteY] {DI = SpriteY_virtuell}
- SUB DI,StartVirtualY {DI = SpriteY (absolut!)}
-
- PUSH AX {WinXMAX}
- MOV AX,WinYMIN
- MOV SI,WinXMIN
- MOV CX,WinYMAX {alte Win* Werte retten...}
-
- MOV DS,[BX + OFFSET SPRITEAD] {!!!DS = ^Spritedaten !!!}
-
- MOV [WinYMIN_],AX {...und in neues DS übernehmen}
- MOV [WinXMIN_],SI
- POP AX
- MOV [WinXMAX_],AX {WinYMAX in CX halten}
-
- MOV AX,[Breite] {AX = Breite in 4er-Gruppen}
- MOV CS:WORD PTR @max_Breite+1,AX
- MOV SI,AX {SI = dto.}
- SHL AX,1
- SHL AX,1 {AX = max_Breite_in_Punkten}
- ADD AX,DX {AX = max_Breite_in_Punkten+SpriteX}
- CMP AX,[WinXMIN_] {liegt rechtes Ende links vom Fensterrand?}
- JL @ToSprite_fertig
- MOV BX,DI {if SpriteY - WinYMIN >= 0 }
- SUB DI,[WinYMIN_] { then starty := 0}
- NEG DI { else starty := -(SpriteY - WinYMIN)}
- MOV BP,DI
- JG @Top_cut
- XOR DI,DI
- @Top_cut: {DI = starty, BP = -(SpriteY - WinYMIN)}
- MOV AX,[Hoehe] {AX = Hoehe (in Zeilen) }
- CMP DI,AX {if starty >= Hoehe then skip_sprite}
- JGE @ToSprite_fertig
- ADD BP,CX {BP = -(SpriteY - WinYMIN) + WinYMAX}
- SUB BP,[WinYMIN_]
- JL @ToSprite_fertig {(etwas frei:) }
- CMP AX,BP {if Hoehe + SpriteY > WinYMAX }
- JG @To_then { then [ endy := WinYMAX - SpriteY }
- DEC AX { if endy < 0 then skip_sprite ] }
- MOV BP,AX { else endy := Hoehe - 1 }
-
- {BP = endy, SI=[@max_Breite+1] = max_Breite_in_4er_Gruppen, }
- {DI = starty, BX = SpriteY, DX=[@akt_SpriteX+1] = SpriteX, }
- {DS = ^Spritedaten, ES = ^Grafikseite}
- @To_then:
- MOV AX,BP
- SUB BP,DI
-
- SHL BP,1
- MOV [End_min_Start],BP {= (endy - starty) * 2 =Yaktuell * 2}
- ADD BX,AX
- SHL BX,1
- MOV BX,CS:[OFFSET gadr + BX] {BX =zeilenadr :=(endy + SpriteY) * LINESIZE}
- MOV [zeilenadr],BX {auch nach [zeilenadr] }
- MOV BP,DX
- MUL SI {AX = endy * max_Breite_in_4er = yoffset}
- MOV [yoffset_],AX {auch nach [yoffset_]}
- SHL DI,1 {DI = starty * 2}
- MOV CS:WORD PTR @Starty_2+1,DI {auch nach [@Starty_2 + 1] }
-
- {kleiner Einschub: anhand des Modusbytes des Sprites entscheiden, ob}
- {eine andere Routine zur Darstellung des Sprites als die gerade ak- }
- {tive benötigt wird und wenn ja, diese in Position bringen! }
- {Verwendete Register: AX und SI }
- MOV AL,[Modus] {Modusbyte des Sprites holen}
- XOR AH,AH
- SHL AX,1
- MOV SI,AX
- MOV SI,CS:[OFFSET Adressen +SI] {Pointer auf zugehörige Routine holen}
- MOV AX,CS:[SI]
- CMP AX,CS:[WORD PTR @Patch1] {ist diese Routine bereits aktiv?}
- JE @no_newcode {ja, nix zu tun}
- PUSH DS {nein, kopiere die Routine an die}
- PUSH CS {entsprechenden Stellen}
- POP DS
- MOV [WORD PTR @Patch1],AX
- MOV [WORD PTR @Patch2],AX
- MOV [WORD PTR @Patch3],AX
- MOV [WORD PTR @Patch4],AX
- INC SI
- INC SI
- LODSW
- MOV [WORD PTR @Patch1+2],AX
- MOV [WORD PTR @Patch2+2],AX
- MOV [WORD PTR @Patch3+2],AX
- MOV [WORD PTR @Patch4+2],AX
- LODSW
- MOV [WORD PTR @Patch1+4],AX
- MOV [WORD PTR @Patch2+4],AX
- MOV [WORD PTR @Patch3+4],AX
- MOV [WORD PTR @Patch4+4],AX
- LODSW
- MOV [WORD PTR @Patch1+6],AX
- MOV [WORD PTR @Patch2+6],AX
- MOV [WORD PTR @Patch3+6],AX
- MOV [WORD PTR @Patch4+6],AX
- LODSW
- MOV [WORD PTR @Patch1+8],AX
- MOV [WORD PTR @Patch2+8],AX
- MOV [WORD PTR @Patch3+8],AX
- MOV [WORD PTR @Patch4+8],AX
- LODSW
- MOV [WORD PTR @Patch1+10],AX
- MOV [WORD PTR @Patch2+10],AX
- MOV [WORD PTR @Patch3+10],AX
- MOV [WORD PTR @Patch4+10],AX
- LODSW
- MOV [WORD PTR @Patch1+12],AX
- MOV [WORD PTR @Patch2+12],AX
- MOV [WORD PTR @Patch3+12],AX
- MOV [WORD PTR @Patch4+12],AX
- LODSW
- MOV [WORD PTR @Patch1+14],AX
- MOV [WORD PTR @Patch2+14],AX
- MOV [WORD PTR @Patch3+14],AX
- MOV [WORD PTR @Patch4+14],AX
-
- POP DS {DS wiederherstellen}
- @no_newcode:
-
-
- {(AX=)[yoffset_] = yoffset }
- { BX = [zeilenadr] = (endy + SpriteY) * LINESIZE}
- { CX = WinYMAX }
- { DI = [@Starty_2 + 1] = starty * 2}
- {(SI = [@max_Breite + 1] = max_Breite_in_4er_) }
- { BP = [@akt_SpriteX + 1]= SpriteX}
- { DS = ^Spritedaten}
- { ES = ^Grafikseite}
- { [end_min_start] = (endy - starty) * 2 = Yaktuell * 2}
- { [@max_Breite + 1] = max_Breite_in_4er_Gruppen }
- @eine_Zeile:
- MOV SI,[end_min_start] {SI = Yaktuell * 2 }
- ADD SI,DI {startx := sprite[WORD PTR sprite[L] + }
- MOV DI,SI { (Yaktuell + starty) * 2] }
- ADD SI,[Left]
- MOV SI,[SI] {SI = startx, DI = (Yaktuell + starty) * 2}
- MOV AX,BP
- MOV DX,AX {AX = DX = SpriteX}
- SUB BP,[WinXMIN_] {BP = SpriteX - WinXMIN}
- ADD AX,SI {AX = bildschirmstartx := SpriteX + startx }
- CMP AX,[WinXMAX_] {if bildschirmstartx > WinXMAX then skip_zeile}
- JG @ToZeile_fertig
- MOV CX,SI {CX = startx}
- SUB AX,[WinXMIN_] {licutoff_in_Punkten := startx}
- JGE @L1 {if bildschirmstartx < WinXMIN then }
- SUB SI,AX { [dec(startx,bildschirmstartx - WinXMIN) }
- XOR AX,AX { bildschirmstartx := WinXMIN }
- MOV CX,BP { licutoff_in_Punkten := -SpriteX] }
- NEG CX
- @L1:
- ADD AX,[WinXMIN_] {CX = [licutoff_] = licutoff_in_Punkten, }
- MOV [licutoff_],CX {SI = startx, AX = bildschirmstartx }
- ADD DI,[Right]
- MOV DI,[DI] {DI = endx := sprite[WORD PTR sprite[R] + }
- { (Yaktuell + starty) * 2] }
- NEG DX {DX = -SpriteX }
- MOV BP,DI
- SUB BP,SI {BP = endx - startx }
- SUB DX,DI {DX = -(SpriteX + endx) }
- ADD DX,[WinXMAX_] {DX = Überhang := WinXMAX - (SpriteX + endx) }
- JNS @kein_Ueberhang_rechts
- ADD BP,DX
- @kein_Ueberhang_rechts: {BP = sichtbare Breite dieser Zeile -1}
- OR BP,BP
- JNS @L6
- @ToZeile_fertig:
- JMP @Zeile_fertig {if Breite <= 0 then skip_zeile }
- @L6:
- ADD BP,4
-
- { AX = bildschirmstartx}
- { BX = [zeilenadr] = (endy + SpriteY) * LINESIZE }
- { CX = [licutoff_] = licutoff_in_Punkten}
- {(DX = (negativer) Überhang (falls Wert < 0) ) }
- {(SI = startx) }
- {(DI = endx) }
- { BP = Breite für diese Zeile in Punkten + 3 }
- { DS = ^Spritedaten}
- { ES = ^Grafikseite}
- { [@max_Breite + 1] = max_Breite_in_4er_) }
- { [end_min_start] = (endy - starty) * 2 =Yaktuell * 2}
- { [@Starty_2 + 1] = starty * 2}
- { [@max_Breite + 1] = max_Breite_in_4er_Gruppen, }
- { [@akt_SpriteX + 1] = SpriteX}
- MOV [bildx],AX {bildschirmstartx retten}
- MOV DX,CX {DX = licutoff_in_Punkten}
- MOV CX,BP
- SHR CX,1
- SHR CX,1 {CX = Breite DIV 4}
- JCXZ @Plane1
-
- {SI = Quellzeiger := sprite[WORD PTR (licutoff_in_Punkten + 0 AND 3) * 2}
- { + (licutoff_in_Punkten + 0) DIV 4 + yoffset }
- MOV SI,DX
- AND SI,3
- SHL SI,1 {SI = ((licutoff_in_Punkten + 0) AND 3) * 2}
- MOV SI,[SI]
- MOV DI,DX
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_] {SI = sprite[WORD PTR (licutoff_...)] }
- { + (licutoff_in_Punkten + i) DIV 4 }
- { + yoffset }
-
- {DI = Zielzeiger := (bildschirmstartx + 0) DIV 4 + zeilenadr}
- MOV DI,AX {DI = bildschirmstartx }
- SHR DI,1
- SHR DI,1
- ADD DI,BX
- MOV BL,AL
- AND BX,3 {BX = (bildschirmstartx + i) AND 3 }
- MOV AH,Translate[BX] {AH = 1,2,4,8 für BX = 0,1,2,3 }
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {Plane auswählen}
-
- XCHG BX,DI
- {CX Bytes von DS:SI nach ES:BX übertragen }
- {Hierher kommt die Routine zur Datenübertragung!}
- @Patch1:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane1:
- MOV DX,[bildx]
- INC DX {DX = bildschirmstartx+1}
- MOV BX,DX
- SHR BX,1
- SHR BX,1 {BX = zielzeiger := (bildschirmstartx + 1) }
- ADD BX,[zeilenadr] { DIV 4 + zeilenadr }
- MOV CX,BP
- DEC CX {CX = Breite dieser Zeile + 3 - 1 }
- SHR CX,1
- SHR CX,1 {CX = Bytes_zu_moven für i = 1 }
- JCXZ @Plane2
- MOV DI,[licutoff_]
- INC DI {DI = (licutoff_in_Punkten + 1) }
- MOV SI,DI
- AND SI,3
- SHL SI,1 {SI = ((licutoff_in_Punkten + 1) AND 3) * 2}
- MOV SI,[SI] {SI = sprite[WORD PTR licutoff_...] }
- SHR DI,1 { + (licutoff_in_Punkten + 1) DIV 4 }
- SHR DI,1 { + yoffset }
- ADD SI,DI
- ADD SI,[yoffset_] {SI = Quellzeiger, }
- {DI = (licutoff_in_Punkten + 1) DIV 4 }
-
- MOV DI,DX {DI = bildschirmstartx + 1}
- AND DI,3 {DI = (bildschirmstartx + 1) AND 3 }
- MOV AH,Translate[DI] {Maske für Portzugriff laden}
- MOV AL,2
- MOV DX,3C4h {Plane anwählen}
- OUT DX,AX
-
- {Hierher kommt die Routine zur Datenübertragung!}
- @Patch2:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane2:
- MOV DX,[bildx]
- ADD DX,2
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,2
- SHR CX,1
- SHR CX,1
- JCXZ @Plane3
- MOV DI,[licutoff_]
- ADD DI,2
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = bildschirmstartx + 2}
- AND DI,3 {DI = (bildschirmstartx + 1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {Hierher kommt die Routine zur Datenübertragung!}
- @Patch3:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane3:
- MOV DX,[bildx]
- ADD DX,3
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,3
- SHR CX,1
- SHR CX,1
- JCXZ @Zeile_fertig
- MOV DI,[licutoff_]
- ADD DI,3
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = bildschirmstartx + 3}
- AND DI,3 {DI = (bildschirmstartx + 1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {Hierher kommt die Routine zur Datenübertragung!}
- @Patch4:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Zeile_fertig:
- MOV AX,[yoffset_]
- @max_Breite:
- SUB AX,1234
- MOV [yoffset_],AX
- MOV BX,[zeilenadr]
- SUB BX,LINESIZE
- MOV [zeilenadr],BX
- SUB WORD PTR [end_min_start],2
- JS @Sprite_fertig
-
- @Starty_2:
- MOV DI,1234
- @akt_SpriteX:
- MOV BP,1234
- JMP @eine_Zeile
-
- @Sprite_fertig:
- POP SI
- MOV AX,SEG @Data
- MOV DS,AX
-
- @noSprite:
- DEC SI
- DEC SI
- JS @fertig
- JMP @zeichne
- @fertig:
-
- POP BP
-
- {Win* Werte wieder auf alte Werte zurücksetzen --wenn nötig:}
- MOV AX,SplitIndex
- CMP AX,NMAX
- JGE @skip {IF (SplitIndex<0) OR (SplitIndex>NMAX) THEN Skip}
-
- MOV AX,BWinLowerRight
- MOV WinLowerRight,AX
- MOV BX,BWinXMIN
- MOV WinXMIN,BX
- MOV SI,BX {SI := WinXMIN}
- SHR BX,1
- SHR BX,1
- MOV WinXMINdiv4,BX {BX := WinXMIN div 4}
- MOV CX,BWinYMIN
- MOV WinYMIN,CX {CX := WinYMIN}
- MOV AX,BWinYMIN_mul_LINESIZE
- MOV WinYMIN_mul_LINESIZE,AX
- ADD AX,BX
- MOV WinYMINmLINESIZEaWinXMINdiv4,AX
- MOV AX,BWinXMAX
- MOV WinXMAX,AX {AX := WinXMAX}
- MOV DX,BWinYMAX
- MOV WinYMAX,DX {DX := WinYMAX}
- SUB DX,CX
- INC DX
- MOV WinHeight,DX
- SUB AX,SI
- INC AX
- MOV WinWidth,AX
- SHR AX,1
- SHR AX,1
- MOV WinWidthDiv4,AL
- @skip:
-
- {"CX := Offset_Adr[Page]" vorbereiten:}
- MOV SI,PAGE {Pagewert * 2 (da Worteinträge!)}
- MOV BX,SI {Pagewert in BX merken!}
- SHL SI,1 {dazu Startadresse des Feldes addieren}
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. Verschiebung korrigieren}
- LODSW {Realisiere "AX := Offset_Adr[Page]"}
- MOV CX,AX {nach CX bringen}
- MOV DI,CRTAddress {DI := CRTAddress }
-
- {Die Grafikseite ist nun fertiggestellt und muß noch angezeigt werden:}
- cli
- mov dx,StatusReg
-
- {Auf "display enable"=0 (d.h.: aktiv) warten, so daß Seitenumschaltung}
- {für HB/LB auf selber Seite geschieht:}
-
- @WaitNotHSyncLoop:
- in al,dx
- and al,1
- jz @WaitNotHSyncLoop
-
- @WaitHSyncLoop:
- in al,dx
- and al,1
- jnz @WaitHSyncLoop
-
- MOV DX,DI {DX := CRTAddress}
- MOV AL,$0D {LB-Startadress-Register}
- OUT DX,AL
- INC DX
-
- MOV AX,CX {AX := Offset_Adr[Page]}
- OUT DX,AL {LB der neuen Startadresse setzen}
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {HB der neuen Startadresse setzen}
- OUT DX,AL
- STI
-
- NEG BX {neuer PAGE-Wert := 1-alter PAGE-Wert, d.h.: }
- ADD BX,1 {IF PAGE = 0 THEN PAGE := 1 ELSE (PAGE = 1) PAGE := 0 }
- MOV PAGE,BX
-
- SHL BX,1 {neuer PAGEADR-Wert := Segment_Adr[PAGE] }
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV AX,[BX]
- MOV PAGEADR,AX
-
- {Jetzt überprüfen, ob gesetzte Zyklus(mindest)zeit abgelaufen ist:}
- @L10:
- MOV AL,TimeFlag {Bit 7 = 0/1 für Zeit ist abgelaufen/läuft noch }
- AND AL,$80
- JE @L10
-
- {Zeitüberwachung für nächsten Zyklus starten:}
- MOV AL,IsAT {ist das ein AT/386? ($0/$80 = ja/nein) }
- OR AL,AL {Zeitmechanismus geht nur auf AT/386 }
- JNE @L11 {anderenfalls keine Zeitüberwachung! }
- MOV TimeFlag,AL {AL = 0 zugleich als Init-Wert benutzen }
- MOV DX,WORD PTR CycleTime {Mindestzykluszeit (in Mikrosekunden) }
- MOV CX,WORD PTR CycleTime+2 {eintragen: CX = HIGH-Word, DX = LOW-Word}
- MOV BX,OFFSET TimeFlag {ES:BX = Zeiger auf TimeFlag, Bit 7 = 0/1}
- MOV AX,DS {für: Zeit läuft noch/ist um }
- MOV ES,AX
- MOV AX,8300h {Zeitüberwachung starten}
- INT 15h
- @L11:
- END; {of ASM}
- END; {of ANIMATE}
-
- PROCEDURE FreeSpriteMem(number:WORD);
- { in: number = Ladenummer des Sprites, das freigegeben werden soll}
- {out: belegter Speicher wurde freigegeben, SPRITEAD[number] auf 0 und}
- { SPRITEPTR[number] auf NIL gesetzt}
- {rem: Spritenummern auf den freigegebenen Bereich sind anschließend}
- { natürlich nicht mehr erlaubt!}
- { War unter "number" kein Sprite geladen, so passiert nichts}
- { Evtl. Spritezyklen müssen durch entsprechend viele Aufrufe dieser}
- { Routine aufgelöst werden.}
- BEGIN
- IF (number<1) OR (number>LoadMAX)
- THEN Error:=Err_InvalidSpriteLoadNumber
- ELSE IF SPRITEPTR[number]<>NIL
- THEN BEGIN
- FreeMem(SPRITEPTR[number],SPRITESIZE[number]);
- SPRITEPTR[number]:=NIL;
- SPRITESIZE[number]:=0;
- SPRITEAD[number]:=0
- END
- END;
-
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- { in: name = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
- { number = Nummer, die das erste Sprite aus diesem File bekommen soll }
- {out: Anzahl der aus dem File gelesenen Sprites (0 = Fehler trat auf) }
- {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein }
- { zelnes Sprite oder eine ganze Spritebibliothek handelt und lädt }
- { alle Spritedaten auf den Heap, und zwar derart, daß die Adresse }
- { immer auf eine Segmentgrenze fällt. Diese Anfangsadressen werden }
- { dann in der Tabelle SPRITEAD[number] abgelegt; sind mehrere Sprites }
- { in der Datei, so werden sie mit fortlaufender Nummer eingetragen, }
- { also number+i }
- LABEL quit_loop;
- VAR p1,p2:Pointer;
- f:FileOfByte;
- count:WORD;
- Header:SpriteHeader;
- tempName:STRING;
- BEGIN
- count:=0; {Zahl der bisher eingelesenen Sprites}
-
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
-
- _assign(f,name);
- {$I-} _reset(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- if (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN {Datei existiert nicht oder nicht unter diesem Pfad}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- loadSprite:=0; exit
- END;
- IF (number=0) or (number>LoadMAX)
- THEN BEGIN
- Error:=Err_InvalidSpritenumber;
- goto quit_loop;
- END;
- WHILE NOT _physicalEOF(f) DO
- BEGIN
- {Zunächst den Spriteheader einlesen: }
- {$I-} {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
- _blockread(f,Header,Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoSprite;
- goto quit_loop;
- END;
- {noch genug Platz da?}
- IF (Header.SpriteLength+15>MaxAvail+SPRITESIZE[number+count])
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- FreeSpriteMem(number+count); {evtl. alten Speicher freigeben}
-
- {Jetzt eigentliche Spritedaten einlesen: }
- getmem(p1,Header.SpriteLength+15); {genug Platz reservieren}
- SPRITESIZE[number+count]:=Header.SpriteLength+15;
- SPRITEPTR [number+count]:=p1;
- IF (LONGINT(p1) mod 16)=0
- THEN p2:=p1 {p2 auf Segmentgrenze bringen}
- ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
-
- MOVE(Header,p2^,Kopf); {Spriteheader auf Heap bringen}
- LONGINT(p1):=LONGINT(p2)+Kopf; {zeigt genau hinter den Header}
-
- {$I-} {jetzt den "Rest" des Sprites laden}
- _blockread(f,p1^,Header.SpriteLength-Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
-
- {der Spritenummer zuordnen:}
- spritead[number+count]:=(longint(p2) shr 16)
- +(longint(p2) and 65535) shr 4;
- INC(count);
-
- IF (NOT _physicalEOF(f)) AND
- ( (NOT f.komprimiert) OR (_logicalEOF(f)) )
- THEN Resync(f)
- END;
-
- quit_loop: ;
- _close(f);
- loadSprite:=count
- END;
-
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- { in: name = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
- { number = 0..255 = Tilenummer für das erste Sprite der Datei }
- {out: Anzahl der aus dem File gelesenen Tiles (0 = Fehler trat auf) }
- {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein }
- { einzelnes Sprite oder eine ganze Spritebibliothek handelt und lädt }
- { alle Sprites, zerlegt diese in Tiles und legt sie in der 4.Grafik- }
- { seite ab, beginnend mit der übergebenen Nummer number }
- { Da eine Kachel 16x16 Punkte groß ist, müssen die Sprites ein Viel- }
- { faches von 16 Punkten in x- und y-Richtung sein }
- { Enthält die Datei mehrere Tiles, so werden sie zeilenweise geladen, }
- { jede Zeile dabei in der Reihenfolge von links nach rechts }
- LABEL quit_loop;
- TYPE split=RECORD loword,hiword:WORD END;
- VAR p1:Pointer;
- ad,p:LONGINT;
- f:FileOfByte;
- count,ZielOfs,step,yoffset:WORD;
- pSeg,pOfs:ARRAY[0..3] OF WORD;
- Breite_in_Tiles,Hoehe_in_Tiles,x,y,i,zeilen:BYTE;
- Header:SpriteHeader;
- tempName:STRING;
- BEGIN
- count:=0; {Zahl der bisher eingelesenen Sprites}
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
- _assign(f,name);
- {$I-} _reset(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- if (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN {Datei existiert nicht oder nicht unter diesem Pfad}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- LoadTile:=0; exit
- END;
- WHILE NOT _physicalEOF(f) DO
- BEGIN
- {Zunächst den Spriteheader einlesen: }
- {$I-} {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
- _blockread(f,Header,Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoTile; {oder Err_NoSprite!}
- goto quit_loop
- END;
- IF (Header.Breite_in_4er_Gruppen MOD 4<>0) OR
- (Header.Hoehe_in_Zeilen MOD 16<>0) {Größe Vielfaches von 16?}
- THEN BEGIN
- Error:=Err_NoTile;
- goto quit_loop
- END
- ELSE BEGIN {ja, Anzahl Tiles in diesem Spritefile ermitteln}
- Breite_in_Tiles:=Header.Breite_in_4er_Gruppen SHR 2;
- Hoehe_in_Tiles :=Header.Hoehe_in_Zeilen SHR 4;
- step:=Breite_in_Tiles*4; {Schrittweite beim laden}
- END;
- IF (Header.SpriteLength>MaxAvail) {noch genug Platz da?}
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- {Jetzt eigentliche Spritedaten einlesen: }
- getmem(p1,Header.SpriteLength); {genug Platz reservieren}
-
- {$I-} {jetzt den "Rest" des Sprites laden}
- _blockread(f,p1^,Header.SpriteLength-Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
-
- ad:=(LONGINT(split(p1).HiWord) SHL 4) + split(p1).LoWord - Kopf;
- FOR i:=0 TO 3 DO
- BEGIN
- p:=ad+Header.Zeiger_auf_Plane[i]; pSeg[i]:=p SHR 4; pOfs[i]:=p AND $F;
- END;
-
- FOR y:=0 TO Pred(Hoehe_in_Tiles) DO
- BEGIN
- yoffset:=y*Breite_in_Tiles*16*(16 DIV 4);
- FOR x:=0 TO Pred(Breite_in_Tiles) DO
- BEGIN
- IF count+number>255
- THEN BEGIN
- Error:=Err_InvalidTileNumber;
- goto quit_loop
- END;
- ZielOfs:=(number+count) SHL 6;
- FOR i:=0 TO 3 DO
- BEGIN
- PORTW[$3C4]:=(TranslateTab[i] SHL 8) + 2;
- FOR zeilen:=0 TO 15 DO
- BEGIN
- move(mem[pSeg[i]:pOfs[i] + yoffset + zeilen*step + x*(16 DIV 4)],
- mem[SCROLLADR:ZielOfs + zeilen*(16 DIV 4)],
- 16 DIV 4);
- END;
- END;
-
- INC(count);
- END;
- END;
- FreeMem(p1,Header.SpriteLength); {Speicher freigeben}
- IF (NOT _physicalEOF(f)) AND
- ( (NOT f.komprimiert) OR (_logicalEOF(f)) )
- THEN Resync(f)
- END;
-
- quit_loop: ;
- _close(f);
- LoadTile:=count
- END;
-
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- { in: (x1,y1) = linke obere Ecke des Bereiches (virtuelle Koord.)}
- { (x2,y2) = dto., rechte untere Ecke}
- {out: (BackX1,BackY1), (BackX2,BackY2) = auf 16er Raster gerundete Koord. }
- { XTiles, YTiles = Breite und Höhe des gewählten Bereiches in Kacheln }
- {rem: Die li. obere Ecke wird nach links oben gezogen, die re. untere nach }
- { rechts unten!}
- { Die Anwendung dieser Routine ist natürlich nur für den Hintergrund- }
- { modus SCROLLING sinnvoll}
- BEGIN
- BackX1:=x1 AND $FFF0; BackX2:=x2 OR $F;
- BackY1:=y1 AND $FFF0; BackY2:=y2 OR $F;
- xtiles:=succ(BackX2-BackX1) shr 4;
- ytiles:=succ(BackY2-BackY1) shr 4;
- IF (xtiles OR ytiles)<=0
- THEN Error:=Err_InvalidCoordinates
- ELSE IF xtiles*ytiles>MaxTiles
- THEN Error:=Err_BackgroundToBig;
- END;
-
- PROCEDURE SetBackgroundMode(mode:BYTE);
- { in: mode = gewünschter Hintergrundmodus STATIC oder SCROLLING}
- {out: Backgroundmode = gesetzter Modus STATIC/SCROLLING}
- BEGIN
- IF (mode<>STATIC) AND (mode<>SCROLLING)
- THEN Error:=Err_InvalidMode
- ELSE Backgroundmode:=mode
- END;
-
- PROCEDURE MakeTileArea(FirstTile:BYTE; TileWidth,TileHeight:INTEGER);
- { in: FirstTile = Anfangsindex der ersten Kachel}
- { TileWidth = Breite (in Kacheln) des zu wiederholenden Rechtecks}
- { TileHeight= dto., Höhe}
- { BackX1,BackY1,BackX2,BackY2= per SetScrollRange()-Aufruf gesetzter}
- { Hintergrundbereich}
- {out: Beginnend mit Kachel FirstTile wurden die TileWidth*TileHeight }
- { nächsten Kacheln als sich wiederholendes Rechteck der Breite }
- { TileWidth und Höhe TileHeight in den Hintergrund übernommen. }
- { Auf diese Art wurde der gesamte definierte Hintergrund gebildet}
- { Bspw. sorgt ein Aufruf der Form MakeTileArea(7,3,2) für folgendes}
- { Layout: }
- { ┌──┬──┬──┬──┬──┬──┬──┬ }
- { │ 7│ 8│ 9│ 7│ 8│ 9│ 7│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { │10│11│12│10│11│12│10│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { │ 7│ 8│ 9│ 7│ 8│ 9│ 7│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { │10│11│12│10│11│12│10│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { . . . . . . . }
- { . . . . . . . }
- {rem: Der Aufruf dieser Routine ist nur sinnvoll, wenn SCROLLING als}
- { Hintergrundmodus verwendet wird und SetScrollRange() aufgerufen}
- { wurde!}
- VAR GY,StartRowTile,
- x,y:INTEGER;
- BEGIN
- IF (TileWidth>0) AND (TileHeight>0)
- THEN BEGIN
- FOR y:=0 TO ytiles-1 DO
- BEGIN
- gy:=BackY1+(y SHL 4); {y-Koordinate für diese Zeile}
- {Index der 1.Tile der aktuellen Zeile berechnen:}
- StartRowTile:=(y MOD TileHeight)*TileWidth+FirstTile;
- FOR x:=0 TO xtiles-1 DO
- PutTile(BackX1+(x SHL 4),gy,StartRowTile+(x MOD TileWidth));
- END
- END
-
- ELSE Error := Err_InvalidCoordinates
- END;
-
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- { in: x,y = virtuelle Koordinate, an die die Kachel plaziert werden soll}
- { TileNr= Nummer der zu plazierenden Kachel}
- {out: - }
- {rem: Der Punkt (x,y) wird zunächst auf 16er Raster gebracht! }
- { Die Anwendung dieser Routine ist nur für den Hintergrund-}
- { modus SCROLLING sinnvoll}
- VAR index:WORD;
- BEGIN
- ASM
- MOV AX,x {berechne relativen X-Abstand vom linken Rand des}
- SUB AX,BackX1 {definierten Bereiches in "x" mittels der Formel:}
- SAR AX,1 { x := ((x AND $FFF0) - BackX1) DIV 16 (nicht: }
- SAR AX,1 {SHR 4)! "AND $FFF0" kann dabei entfallen, da in}
- SAR AX,1 {BackX1 die letzte Hex-Ziffer $0 ist! }
- SAR AX,1
- MOV x,AX
-
- MOV AX,y {dto. für Abstand der y-Koordinate vom oberen }
- SUB AX,BackY1 {Rand: y := ((y AND $FFF0) - BackY1) DIV 16 }
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV y,AX
- END;
-
- IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
- THEN Error:=Err_InvalidCoordinates
- ELSE BEGIN {jede Kachelzeile ist XTiles breit, jede Kachel 16x16 Punkte}
- index:=y*XTiles+x; {eigentlich: (x MOD XTiles)}
- BackTile[Succ(index)]:=TileNr; {"Succ", um BackTile[0] freizuhalten}
- END;
- END;
-
- FUNCTION GetTile(x,y:INTEGER):BYTE;
- { in: x,y = virtuelle Koordinate, von der die Kachel gelesen werden soll}
- {out: Nummer der Kachel an dieser Stelle}
- {rem: Der Punkt (x,y) wird zunächst auf 16er Raster gebracht!}
- { Liegt der Punkt außerhalb des definierten Bereiches, so wird die}
- { Offscreen-Kachel BackTile[0] zurückgegeben}
- BEGIN
- ASM
- MOV AX,x {berechne relativen X-Abstand vom linken Rand des}
- SUB AX,BackX1 {definierten Bereiches in "x" mittels der Formel:}
- SAR AX,1 { x := ((x AND $FFF0) - BackX1) DIV 16 (nicht: }
- SAR AX,1 {SHR 4)! "AND $FFF0" kann dabei entfallen, da in}
- SAR AX,1 {BackX1 die letzte Hex-Ziffer $0 ist! }
- SAR AX,1
- MOV x,AX
-
- MOV AX,y {dto. für Abstand der y-Koordinate vom oberen }
- SUB AX,BackY1 {Rand: y := ((y AND $FFF0) - BackY1) DIV 16 }
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV y,AX
- END;
-
- IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
- THEN GetTile:=BackTile[0]
- ELSE GetTile:=BackTile[y*XTiles+x+1]
- END;
-
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- { in: TileNr= Nummer der zu plazierenden Kachel}
- {out: - }
- {rem: Alle Bildschirmteile, die außerhalb des durch SetBackground-}
- { ScrollRange definierten Bereiches liegen, erhalten TileNr als}
- { Muster zugewiesen }
- { Die Anwendung dieser Routine ist nur für den Hintergrund- }
- { modus SCROLLING sinnvoll}
- BEGIN
- BackTile[0]:=TileNr
- END;
-
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- { in: Sp = SpriteLADEnummer, dessen Modusbyte verändert werden soll}
- {out: M = Methode, mit der Sp ab sofort dargestellt werden soll: }
- { Display_NORMAL, Display_FAST, Display_SHADOW oder }
- { Display_SHADOWEXACT }
- {rem: Existiert das Sprite noch nicht oder ist der Modus nicht er- }
- { laubt, so geschieht nichts! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF ad=0 THEN Error:=Err_InvalidSpriteNumber {Sprite muß schon geladen sein}
- ELSE IF (M<Display_NORMAL) OR (M>Display_SHADOWEXACT)
- THEN Error:=Err_InvalidMode {nur diese 4 Modi sind zulässig}
- ELSE MEM[ad:Modus]:=M
- END;
-
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- { in: Sp = SpriteLADEnummer, dessen Modusbyte abgefragt werden soll}
- {out: Methode, die für Sp momentan gesetzt ist: Display_NORMAL, }
- { Display_FAST, Display_SHADOW, Display_SHADOWEXACT bzw. }
- { Display_UNKNOWN, wenn das Sprite noch nicht geladen wurde! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF (ad=0)
- THEN GetModeByte:=Display_UNKNOWN {Sprite noch nicht geladen}
- ELSE GetModeByte:=MEM[SPRITEAD[Sp]:Modus]
- END;
-
- PROCEDURE FillBackground(color:BYTE);
- { in: color = Füllfarbe für die Hintergrundseite BACKGNDPAGE }
- { BACKGNDADR = Zeiger auf Hintergrundspeicher}
- {out: Die Grafikseite BACKGNDPAGE wurde mit der Farbe "Color" gefüllt}
- {rem: Die Routine ist nur für den Hintergrundmodus STATIC sinnvoll }
- BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- FillChar(MEM[BACKGNDADR:0],4*PAGESIZE,color);
- END;
-
- PROCEDURE FillPage(pa:WORD; color:BYTE);
- { in: pa = die Seite, die gefüllt werden soll (0..3)}
- { color = Füllfarbe für die Seite}
- {out: Grafikseite "pa" wurde mit der Farbe "Color" gefüllt}
- {rem: Sinnvoll sind nur die Seiten 0,1 und BACKGNDPAGE, }
- { jedoch ist SCROLLPAGE ebenfalls erlaubt}
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE IF pa=BACKGNDPAGE
- THEN FillBackground(color)
- ELSE BEGIN
- portw[$3C4]:=$0F02; {im Map-Mask Register alle 4 Ebenen selektieren}
- fillchar(MEM[Segment_Adr[pa]:0],PAGESIZE,Color)
- END;
- END;
-
- PROCEDURE GetBackgroundFromPage(pa:WORD);
- {in : pa = 0 oder 1 }
- {out: - }
- {rem: Der Hintergrundspeicher BACKGNDPAGE wird mit dem Inhalt der }
- { angegebenen Grafikseite gefüllt.}
- { Die Routine ist nur für den Hintergrundmodus STATIC sinnvoll}
- VAR p:POINTER;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- ASM
- MOV ES,BACKGNDADR
- MOV SI,pa
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV DS,AX
- XOR SI,SI
- XOR DI,DI
-
- MOV DX,3CEh
- MOV AX,0004h {Leseplane 0}
- MOV BX,PAGESIZE / 2
-
- {DS:SI = Quellzeiger, ES:DI = Zielzeiger, BX = Anzahl Worte }
- {AX = Zugriffsmaske auf Leseplane 0, DX = Registerport dafür}
-
- CLI
- OUT DX,AX {Plane 0 anwählen}
- MOV CX,BX
- REP MOVSW {Planedaten speichern}
- XOR SI,SI {SI rücksetzen}
-
- INC AH {Plane 1 anwählen}
- OUT DX,AX
- MOV CX,BX
- REP MOVSW
- XOR SI,SI
-
- INC AH {Plane 2 anwählen}
- OUT DX,AX
- MOV CX,BX
- REP MOVSW
- XOR SI,SI
-
- INC AH {Plane 3 anwählen}
- OUT DX,AX
- MOV CX,BX
- REP MOVSW
-
- STI
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- END;
- END;
-
- PROCEDURE WritePage(name:STRING; pa:WORD);
- { in: name = Filename für das abzuspeichernde Bild}
- { pa = abzuspeichernde Seite (0..3) }
- { PAGESIZE = Größe einer Bitplane }
- { PICHeader= einzutragende Kennung für Bilderdateien}
- {out: - }
- {rem: Die Grafik auf Seite "pa" wurde in der Datei "name" als Bitmap abgelegt}
- { Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes groß: 320x200 Punkte zu je }
- { 1 Byte plus Length(PICHeader) als Kennung}
- VAR f:FILE;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- {$I-}
- Assign(f,name); fehler:=IOResult<>0;
- Rewrite(f,1); fehler:=fehler OR (IOResult<>0);
- BlockWrite(f,PICHeader[1],Length(PICHeader));
- fehler:=fehler OR (IOResult<>0);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF fehler
- THEN BEGIN
- {$I-} Close(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_FileIO; exit
- END;
-
- IF pa<>BACKGNDPAGE
- THEN BEGIN {VRAM nach Disk}
- port[$3ce]:=5; {alten Lese-/Schreibmodus merken}
- oldMode:=port[$3cf];
- port[$3cf]:=$40; {Lesemodus 0 setzen}
- FOR i:=0 TO 3 DO
- BEGIN
- portw[$3CE]:=4+(i shl 8); {Lese-Plane anwählen}
- {$I-}
- BlockWrite(f,mem[Segment_Adr[pa]:0],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- END;
- port[$3ce]:=5; {alten Lese-/Schreibmodus setzen}
- port[$3cf]:=oldMode;
- END
- ELSE BEGIN {RAM nach Disk}
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- BlockWrite(f,MEM[BACKGNDADR:BACKtab[i]],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- END
- END;
- {$I-}
- Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE LoadPage(name:STRING; pa:WORD);
- { in: name = Filename für das zu ladende Bild}
- { pa = Zielseite, in die das Bild geladen werden soll (0..3) }
- { PAGESIZE = Größe einer Bitplane }
- { PICHeader= Kennung für Bilderdateien }
- {out: - }
- {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Seite "pa" geladen}
- VAR f:FileOfByte;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- s:STRING[3];
- splane:WORD;
- p1,p2:POINTER;
- tempName:STRING;
- TYPE tempArray=ARRAY[1..PAGESIZE] OF BYTE;
- VAR temp:^tempArray;
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
- {$I-}
- _Assign(f,name); fehler:=IOResult<>0;
- _Reset(f); fehler:=fehler OR (IOResult<>0);
- s[0]:=PICHeader[0];
- _BlockRead(f,s[1],Length(PICHeader));
- fehler:=fehler OR (IOResult<>0) OR (CompressError<>CompressErr_NoError);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF fehler
- THEN BEGIN
- {$I-} _Close(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- exit
- END
- ELSE IF (_FileSize(f)<>4*PAGESIZE+Length(PICHeader)) OR (s<>PICHeader)
- THEN BEGIN
- {$I-} _Close(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_NoPicture;
- exit
- END;
-
- IF pa<>BACKGNDPAGE
- THEN BEGIN {Disk nach VRAM}
- ASM cli END;
- port[$3ce]:=5; {alten Lese-/Schreibmodus merken}
- oldMode:=port[$3cf];
- New(temp);
- ASM sti END;
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- _BlockRead(f,temp^[1],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- splane:=2+(TranslateTab[i] shl 8); {welche Schreib-Plane}
- p1:=@temp^[1];
- p2:=ptr(Segment_Adr[pa],0);
- ASM
- cli
- mov dx,$3CE {Schreibmodus 0 wählen}
- mov ax,$4005
- out dx,ax
-
- mov ax,splane {Schreibplane anwählen}
- mov dx,$3C4
- out dx,ax
-
- les di,p2
- lds si,p1
- mov cx,PAGESIZE SHR 1
- rep movsw
-
- mov ax,SEG @DATA
- mov ds,ax
- sti
- END;
-
- END;
- portw[$3ce]:=oldMode SHL 8 + 5; {alten Lese-/Schreibmodus setzen}
- Dispose(temp);
- END
- ELSE BEGIN {Disk nach RAM}
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- _BlockRead(f,MEM[BACKGNDADR:BACKtab[i]],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- END
- END;
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0) OR (CompressError<>CompressErr_NoError);
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE WriteBackgroundPage(name:STRING);
- { in: name = Filename für das abzuspeichernde Hintergrundbild}
- { BACKGNDPAGE= abzuspeichernde Seite (=2) }
- { PAGESIZE = Größe einer Bitplane }
- { PICHeader = einzutragende Kennung für Bilderdateien}
- {out: - }
- {rem: Die Grafik der Hintergrundseite wurde in der Datei "name" abgelegt}
- { Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes groß: 320x200 Punkte }
- { zu je 1 Byte plus Length(PICHeader) als Kennung}
- { Die Routine ist nur für den Hintergrundmodus STATIC sinnvoll }
- BEGIN
- WritePage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE LoadBackgroundPage(name:STRING);
- { in: name = Filename für das zu ladende Hintergrundbild}
- { BACKGNDPAGE= Zielseite, in die das Bild geladen werden soll (=2) }
- { PAGESIZE = Größe einer Bitplane }
- { PICHeader= Kennung für Bilderdateien }
- {out: - }
- {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Hintergrundseite}
- { BACKGNDPAGE geladen}
- { Die Routine ist nur für den Hintergrundmodus STATIC sinnvoll}
- BEGIN
- LoadPage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE FadeIn(pa,ti,style:WORD);
- { in: pa = Seite, die auf die aktuelle Seite eingeblendet werden soll}
- { ti = Zeit in Millisekunden, in der dies geschehen soll}
- { style = Algorithmus der dafür benutzt werden soll}
- { 1-PAGE = aktuell sichtbare Seite}
- {out: Error = Err_InvalidFade, falls nicht zulässiger Alg. gewählt wurde}
- {rem: Grafikmodus muß natürlich bereits initialisiert worden sein}
- { Sinnvoll ist eigentlich nur pa=BACKGNDPAGE}
-
- PROCEDURE WipeIn(pa,time:WORD);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST hoehe =40; {Teiler von Succ(YMAX)}
- breite=40; {Teiler von Succ(XMAX)}
- br_x =Succ(XMAX) DIV breite; {Blöcke in X-Richtung}
- br_y =Succ(YMAX) DIV hoehe; {Blöcke in Y-Richtung}
- n=hoehe*br_x; {Anzahl Aufrufe der Verzögerungsschleife}
- VAR i,x,y,ploty,plotx:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- p:POINTER;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- FOR i:=0 TO pred(hoehe) DO
- FOR x:=0 TO pred(br_x) DO
- BEGIN
- FOR y:=0 TO pred(br_y) DO
- BEGIN
- IF ODD(x)
- THEN ploty:=y*hoehe+i +StartVirtualY
- ELSE ploty:=y*hoehe+(hoehe-1-i)+StartVirtualY;
- plotx:=x*breite +StartVirtualX;
- p:=GetImage(plotx,ploty,plotx+pred(breite),ploty,pa);
- PutImage(plotx,ploty,p,1-PAGE);
- FreeImageMem(p);
- END; {of FOR y}
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR x}
- END;
-
- PROCEDURE Chaos(pa,time:WORD;m:BYTE);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { m = Art, wie das geschehen soll (1..14)}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(XMAX)*Succ(YMAX); {Anzahl Bildschirmpunkte}
- {gute Parameter sind z.B. Summen von Zweierpotenzen +1}
- para:ARRAY[1..14] OF WORD=
- (13477,65,337,129,257,513,769,1025,481,4097,5121,177,16385,16897);
- VAR i,k,x,y:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- rand:WORD;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- rand:=0;
- IF (m<1) OR (m>14) THEN m:=1;
- k:=para[m];
- temp:=0.0182*time/n;
- FOR i:=0 TO 65535 DO
- BEGIN
- ASM {berechne: "x := rand MOD 320" und "y := rand DIV 320"}
- XOR DX,DX
- MOV AX,rand
- MOV BX,XMAX+1
- DIV BX
- MOV y,AX
- MOV x,DX
- END;
- IF y<=YMAX
- THEN PutPixel(StartVirtualX+x,StartVirtualY+y,
- PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
- ASM {berechne: rand:=rand*k+1}
- MOV AX,rand
- MUL k
- INC AX
- MOV rand,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR i}
- END;
-
- PROCEDURE Chaos2(pa,time:WORD;m:BYTE);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { m = Art, wie das geschehen soll (1..1)}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(XMAX)*Succ(YMAX); {Anzahl Bildschirmpunkte}
- para:ARRAY[1..1] OF WORD=
- (39551);
- VAR i,k,x,y:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- rand:WORD;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- rand:=0;
- IF (m<1) OR (m>1) THEN m:=1;
- k:=para[m];
- temp:=0.0182*time/n;
- FOR i:=0 TO 65535 DO
- BEGIN
- ASM {berechne: "x:=rand MOD 320" und "y:=rand DIV 320"}
- XOR DX,DX
- MOV AX,rand
- MOV BX,XMAX+1
- DIV BX
- MOV y,AX
- MOV x,DX
- END;
- PutPixel(StartVirtualX+x,StartVirtualY+y,
- PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
- ASM {berechne: rand:=(rand+k) MOD n}
- XOR DX,DX
- MOV AX,rand
- ADD AX,k
- JNC @normal
- ADD AX,(65536-n) {Overflow, also korrigieren}
- @normal:
- CMP AX,n
- JB @ok
- SUB AX,n
- @ok:
- MOV rand,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR i}
- END;
-
- PROCEDURE SweepVertical(pa,time:WORD; down:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { down = TRUE/FALSE für: von oben nach unten/umgekehrt }
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(YMAX); {Anzahl Aufrufe der Verzögerungsschleife }
- VAR y,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF down
- THEN FOR y:=0+StartVirtualY TO YMAX+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR y:=YMAX+StartVirtualY DOWNTO 0+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE SweepHorizontal(pa,time:WORD; left_to_right:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { left_to_right=TRUE/FALSE für: von links nach rechts/umgekehrt}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(XMAX); {Anzahl Aufrufe der Verzögerungsschleife }
- VAR x,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF left_to_right
- THEN FOR x:=0+StartVirtualX TO XMAX+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR x:=XMAX+StartVirtualX DOWNTO 0+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE ScrollVertical(pa,time:WORD; up:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { up = TRUE/FALSE für: von unten nach oben/umgekehrt }
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- LABEL oneLine1,oneLine2,oneLine3,oneLine4;
- CONST n=Succ(YMAX); {Anzahl Aufrufe der Verzögerungsschleife }
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF pa<>BACKGNDPAGE
- THEN BEGIN
- IF up
- THEN BEGIN {nach oben scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,YMAX*LINESIZE+(LINESIZE-1) {DX:BX = ^Quelldaten}
-
- MOV AX,YMAX {AX = Zeilenzähler}
-
- oneLine2:
- STD {rückwärts moven!}
- MOV SI,ES {zuerst alten Inhalt nach oben rollen:}
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1) {von vorletzter Grafikzeile}
- MOV DI,YMAX*LINESIZE+(LINESIZE-1) {nach letzter Grafikzeile}
- MOV CX,YMAX*LINESIZE {199 Zeilen}
- REP MOVSB
-
- MOV DS,DX {jetzt neue Zeile sichtbar machen:}
- MOV SI,BX {DS:SI = ^zu movende Zeile}
- MOV CX,LINESIZE {1 Zeile}
- REP MOVSB
-
- SUB BX,LINESIZE {Quellzeiger weitersetzen}
-
- {--- Einschub für Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- CLD {sicher ist sicher!}
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- Einschub Ende}
-
- DEC AX {alle Zeilen durch?}
- JNS oneLine2 {nein, nächste Zeile}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {nach unten scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1-PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE {DX:BX = ^Quelldaten}
-
- MOV AX,YMAX {AX = Zeilenzähler}
-
- oneLine1:
- MOV SI,ES {zuerst alten Inhalt nach oben rollen:}
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,1*LINESIZE {von Grafikzeile 1}
- MOV DI,0*LINESIZE {nach Grafikzeile 0}
- MOV CX,YMAX*LINESIZE {199 Zeilen}
- REP MOVSB
-
- MOV DS,DX {jetzt neue Zeile sichtbar machen:}
- MOV SI,BX {DS:SI = ^zu movende Zeile}
- MOV CX,LINESIZE {1 Zeile}
- REP MOVSB
-
- ADD BX,LINESIZE {Quellzeiger weitersetzen}
-
- {--- Einschub für Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- Einschub Ende}
-
- DEC AX {alle Zeilen durch?}
- JNS oneLine1 {nein, nächste Zeile}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END
-
- ELSE BEGIN {pa = BACKGNDPAGE, also von RAM nach VRAM}
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- IF up
- THEN BEGIN {nach oben scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^sichtbare Seite}
-
- PUSH DS
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse }
- {(für pa=BACKGNDPAGE id. zu BACKGNADR)}
- PUSH BP
-
- MOV BP,AX
- MOV BX,YMAX*LINESIZE+(LINESIZE-1)-1 {BP:BX = ^Quelldaten}
-
- MOV AX,YMAX {AX = Zeilenzähler}
-
- oneLine4:
- MOV SI,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
- MOV AX,SI
-
- STD {rückwärts moven!}
- MOV SI,ES {zuerst alten Inhalt nach oben rollen:}
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1) {von vorletzter Grafikzeile}
- MOV DI,YMAX*LINESIZE+(LINESIZE-1) {nach letzter Grafikzeile}
- MOV CX,YMAX*LINESIZE {199 Zeilen}
- REP MOVSB
-
- PUSH AX
- MOV DX,3CEh {Writemode 0 setzen}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
- MOV AX,0102h {Writeplane 0 selektieren}
- OUT DX,AX
- MOV DS,BP {jetzt neue Zeile sichtbar machen:}
- MOV SI,BX {DS:SI = ^zu movende Zeile}
- DEC DI {DI um 1 verringern wg. Wort-Zugriffen}
- MOV CX,LINESIZE / 2 {1 Zeile}
- REP MOVSW
-
- SHL AH,1 {Writeplane 1 selektieren}
- OUT DX,AX
- ADD SI,PAGESIZE+LINESIZE
- MOV CX,LINESIZE / 2 {1 Zeile}
- ADD DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {Writeplane 2 selektieren}
- OUT DX,AX
- ADD SI,PAGESIZE+LINESIZE
- MOV CX,LINESIZE / 2 {1 Zeile}
- ADD DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {Writeplane 3 selektieren}
- OUT DX,AX
- ADD SI,PAGESIZE+LINESIZE
- MOV CX,LINESIZE / 2 {1 Zeile}
- ADD DI,LINESIZE
- REP MOVSW
-
- MOV AH,$F {alle 4 Planes selektieren}
- OUT DX,AX
-
- SUB BX,LINESIZE {Quellzeiger weitersetzen}
- POP AX
-
- {--- Einschub für Zeitbedingung:}
- MOV SI,BP {temporäres BP}
- POP BP {altes BP von TP}
- PUSH AX {alle noch relevanten Register retten}
- PUSH BX
- PUSH SI
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP SI
- POP BX
- POP AX
- PUSH BP
- MOV BP,SI
- {--- Einschub Ende}
-
- DEC AX {alle Zeilen durch?}
- JNS oneLine4 {nein, nächste Zeile}
-
- POP BP
- POP DS
- END;
- END
- ELSE BEGIN {nach unten scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1-PAGE] = ^sichtbare Seite}
-
- PUSH DS
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse }
- {(für pa=BACKGNDPAGE id. zu BACKGNADR)}
- PUSH BP
-
- MOV BP,AX
-
- MOV DX,AX
- MOV BX,0*LINESIZE {DX:BX = ^Quelldaten}
-
- MOV AX,YMAX {AX = Zeilenzähler}
-
- oneLine3:
- MOV SI,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
- MOV AX,SI
-
- MOV SI,ES {zuerst alten Inhalt nach oben rollen:}
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,1*LINESIZE {von Grafikzeile 1}
- MOV DI,0*LINESIZE {nach Grafikzeile 0}
- MOV CX,YMAX*LINESIZE {199 Zeilen}
- REP MOVSB
-
- PUSH AX
- MOV DX,3CEh {Writemode 0 setzen}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
- MOV AX,0102h {Writeplane 0 selektieren}
- OUT DX,AX
- MOV DS,BP {jetzt neue Zeile sichtbar machen:}
- MOV SI,BX {DS:SI = ^zu movende Zeile}
- MOV CX,LINESIZE / 2 {1 Zeile}
- REP MOVSW
-
- SHL AH,1 {Writeplane 1 selektieren}
- OUT DX,AX
- ADD SI,PAGESIZE-LINESIZE
- MOV CX,LINESIZE / 2 {1 Zeile}
- SUB DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {Writeplane 2 selektieren}
- OUT DX,AX
- ADD SI,PAGESIZE-LINESIZE
- MOV CX,LINESIZE / 2 {1 Zeile}
- SUB DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {Writeplane 3 selektieren}
- OUT DX,AX
- ADD SI,PAGESIZE-LINESIZE
- MOV CX,LINESIZE / 2 {1 Zeile}
- SUB DI,LINESIZE
- REP MOVSW
-
- MOV AH,$F {alle 4 Planes selektieren}
- OUT DX,AX
-
- ADD BX,LINESIZE {Quellzeiger weitersetzen}
- POP AX
-
- {--- Einschub für Zeitbedingung:}
- MOV SI,BP {temporäres BP}
- POP BP {altes BP von TP}
- PUSH AX {alle noch relevanten Register retten}
- PUSH BX
- PUSH SI
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP SI
- POP BX
- POP AX
- PUSH BP
- MOV BP,SI
- {--- Einschub Ende}
-
- DEC AX {alle Zeilen durch?}
- JNS oneLine3 {nein, nächste Zeile}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
-
- POP BP
- POP DS
- END;
- END;
- END;
- END;
-
- PROCEDURE ScrollHorizontal(pa,time:WORD; left:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- { left = TRUE/FALSE für: von links nach rechts/umgekehrt }
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- LABEL oneColumn1,oneColumn2,oneColumn3,oneColumn4;
- CONST n=Pred(LINESIZE); {Anzahl Aufrufe der Verzögerungsschleife}
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF pa<>BACKGNDPAGE
- THEN BEGIN
- IF left
- THEN BEGIN {nach links scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
-
- MOV AX,LINESIZE-1 {AX = Spaltenzähler}
-
- oneColumn2: {alten Schirminhalt nach rechts schieben:}
- MOV SI,ES
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,PAGESIZE-2
- MOV DI,PAGESIZE-1
- MOV CX,PAGESIZE-1
- STD
- REP MOVSB
- CLD
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP Daten}
- MOV CX,YMAX+1 {CX = Zeilenzähler}
-
- MOV SI,AX
- XOR DI,DI
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^Quelldaten}
-
- @oneRow: {erste Spalte erneuern:}
- MOVSB
- ADD SI,BX {auf nächste Zeile positionieren:}
- ADD DI,BX {geht, weil BX + 1 = LINESIZE}
- LOOP @oneRow
-
- {--- Einschub für Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- Einschub Ende}
-
- DEC AX {alle Spalten durch?}
- JNS oneColumn2 {nein, nächste Spalte}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {nach rechts scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
-
- MOV AX,0 {AX = Spaltenzähler}
-
- oneColumn1: {alten Schirminhalt nach links schieben:}
- MOV SI,ES
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,1
- XOR DI,DI
- MOV CX,PAGESIZE-1
- REP MOVSB
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP Daten}
- MOV CX,YMAX+1 {CX = Zeilenzähler}
-
- MOV SI,AX
- MOV DI,LINESIZE-1
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^Quelldaten}
-
- @oneRow: {letzte Spalte erneuern:}
- MOVSB
- ADD SI,BX {auf nächste Zeile positionieren:}
- ADD DI,BX {geht, weil BX + 1 = LINESIZE}
- LOOP @oneRow
-
- {--- Einschub für Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- Einschub Ende}
-
- INC AX {alle Spalten durch?}
- CMP AX,LINESIZE
- JB oneColumn1 {nein, nächste Spalte}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END
- ELSE BEGIN {pa = BACKGNDPAGE, also von RAM nach VRAM}
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
- IF left
- THEN BEGIN {nach links scrollen}
- ASM
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
- MOV AX,LINESIZE-1 {Spaltenzaehler}
-
- oneColumn4: {alten Schirminhalt nach rechts schieben:}
- MOV SI,DX
- MOV DI,AX
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
- MOV DX,SI
- MOV AX,DI
-
- MOV SI,ES
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,PAGESIZE-2
- MOV DI,PAGESIZE-1
- MOV CX,PAGESIZE-1
- STD
- REP MOVSB
- CLD
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP Daten}
- MOV CX,YMAX+1 {CX = Zeilenzähler}
-
- MOV SI,AX {Spaltenzaehler}
- XOR DI,DI
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^Quelldaten}
-
- PUSH AX
- PUSH DX
- MOV DX,3CEh {Writemode 0 setzen}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
-
- @oneRow0: {erste Spalte erneuern:}
- MOV AX,0802h {Writeplane 3 selektieren}
- OUT DX,AX
- MOV AL,[SI +3*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0402h {Writeplane 2 selektieren}
- OUT DX,AX
- MOV AL,[SI +2*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0202h {Writeplane 1 selektieren}
- OUT DX,AX
- MOV AL,[SI +1*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0102h {Writeplane 0 selektieren}
- OUT DX,AX
- MOVSB
- ADD SI,BX {auf nächste Zeile positionieren:}
- ADD DI,BX {geht, weil BX + 1 = LINESIZE}
- LOOP @oneRow0
-
-
- {--- Einschub für Zeitbedingung:}
- PUSH ES {alle noch relevanten Register retten}
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- {--- Einschub Ende}
-
- POP DX
- POP AX
- DEC AX {alle Spalten durch?}
- JNS oneColumn4 {nein, nächste Spalte}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {nach rechts scrollen}
- ASM
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
-
- MOV AX,0 {AX = Spaltenzähler}
-
- oneColumn3: {alten Schirminhalt nach links schieben:}
- MOV SI,DX
- MOV DI,AX
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
- MOV DX,SI
- MOV AX,DI
-
- MOV SI,ES
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,1
- XOR DI,DI
- MOV CX,PAGESIZE-1
- REP MOVSB
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP Daten}
- MOV CX,YMAX+1 {CX = Zeilenzähler}
-
- MOV SI,AX
- MOV DI,LINESIZE-1
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^Quelldaten}
-
- PUSH AX
- PUSH DX
- MOV DX,3CEh {Writemode 0 setzen}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
-
- @oneRow: {letzte Spalte erneuern:}
- MOV AX,0802h {Writeplane 3 selektieren}
- OUT DX,AX
- MOV AL,[SI +3*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0402h {Writeplane 2 selektieren}
- OUT DX,AX
- MOV AL,[SI +2*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0202h {Writeplane 1 selektieren}
- OUT DX,AX
- MOV AL,[SI +1*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0102h {Writeplane 0 selektieren}
- OUT DX,AX
- MOVSB
- ADD SI,BX {auf nächste Zeile positionieren:}
- ADD DI,BX {geht, weil BX + 1 = LINESIZE}
- LOOP @oneRow
-
- {--- Einschub für Zeitbedingung:}
- PUSH ES {alle noch relevanten Register retten}
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- {--- Einschub Ende}
-
- POP DX
- POP AX
-
- INC AX {alle Spalten durch?}
- CMP AX,LINESIZE
- JB oneColumn3 {nein, nächste Spalte}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END
- END;
-
- PROCEDURE CircleIn(pa,time:WORD);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefähre Zeit (in Millisekunden), in der das geschehen soll}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST centerX=XMAX DIV 2; {Bildschirmmitte}
- centerY=YMAX DIV 2;
- k=189; {Anzahl Kreise := sqrt(centerX² + centerY²), aufgerundet}
- adjust=0.707106781; {Kompensation in Diagonalrichtung = 1/sqrt(2) }
- n=TRUNC(k/adjust); {Anzahl Aufrufe der Verzögerungsschleife}
- VAR radqu,x,y,x0,y0,u1,u2,u3,u4,v1,v2,v3,v4:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- radius,temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- x0:=centerX + StartVirtualX;
- y0:=centerY + StartVirtualY;
- {FOR true_radius:=1 TO k STEP 1/adjust ist in Pascal leider nicht möglich!}
- radius:=0.0;
- REPEAT
- radqu:=TRUNC(sqr(radius));
- FOR x:=0 TO TRUNC(radius/sqrt(2)) DO {Oktanden berechnen}
- BEGIN
- y:=TRUNC(sqrt(radqu-sqr(x))); {Satz des Pythagoras}
- u1:=x0-x; v1:=y0-y; {Achsen- und Punktsymmetrie ausnutzen}
- u2:=x0+x; v2:=y0+y;
- u3:=x0-y; v3:=y0-x;
- u4:=x0+y; v4:=y0+x;
- PutPixel(u1,v1,PageGetPixel(u1,v1,pa));
- PutPixel(u1,v2,PageGetPixel(u1,v2,pa));
- PutPixel(u2,v1,PageGetPixel(u2,v1,pa));
- PutPixel(u2,v2,PageGetPixel(u2,v2,pa));
- PutPixel(u3,v3,PageGetPixel(u3,v3,pa));
- PutPixel(u3,v4,PageGetPixel(u3,v4,pa));
- PutPixel(u4,v3,PageGetPixel(u4,v3,pa));
- PutPixel(u4,v4,PageGetPixel(u4,v4,pa));
- END;
- radius:=radius+adjust;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- UNTIL radius>=k;
- END;
-
- BEGIN {of FadeIn}
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE CASE style OF
- Fade_Squares :WipeIn(pa,ti);
- Fade_Moiree1..Fade_Moiree14:Chaos(pa,ti,style+1-Fade_Moiree1);
- Fade_SweepInFromTop: SweepVertical(pa,ti,TRUE);
- Fade_SweepInFromBottom: SweepVertical(pa,ti,FALSE);
- Fade_SweepInFromLeft: SweepHorizontal(pa,ti,TRUE);
- Fade_SweepInFromRight: SweepHorizontal(pa,ti,FALSE);
- Fade_ScrollInFromTop: ScrollVertical(pa,ti,TRUE);
- Fade_ScrollInFromBottom:ScrollVertical(pa,ti,FALSE);
- Fade_ScrollInFromLeft: ScrollHorizontal(pa,ti,TRUE);
- Fade_ScrollInFromRight: ScrollHorizontal(pa,ti,FALSE);
- Fade_Circles : CircleIn(pa,ti);
- Fade_Moiree15:Chaos2(pa,ti,style+1-Fade_Moiree15);
- else Error:=Err_InvalidFade
- END;
- END;
-
-
- PROCEDURE IntroScroll(n,wait:WORD);
- { in: n = Anzahl Zeilen, die hochgescrollt werden sollen}
- { wait = Zeit (in ms), die nach jeder Zeile gewartet werden soll}
- {rem: Das Scrollen beginnt immer auf Seite 0 (=$A000:0000)}
- { Hinterher muß das Kommando "Screen(1-page)" ausgeführt werden!}
- BEGIN
- Screen(0); {auf $A000:0000 positionieren}
- ASM
- XOR SI,SI {Adresse von Seite 0 ermitteln = $A000:0000}
- AND SI,3 {Pagewert * 2 (da Worteinträge!)}
- SHL SI,1 {dazu Startadresse des Feldes addieren}
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. Verschiebung korrigieren}
- LODSW {und Wert holen}
- MOV BX,AX
- MOV CX,n
- MOV SI,wait
-
- @oneline:
- ADD BX,LINESIZE
-
- CLI {Darf keinenfalls unterbrochen werden!}
- MOV DX,StatusReg
- @WaitNotHSyncLoop:
- in al,dx
- and al,1
- jz @WaitNotHSyncLoop
- @WaitHSyncLoop:
- in al,dx
- and al,1
- jz @WaitHSyncLoop
-
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-Startadress-Register}
- OUT DX,AL
- INC DX
-
- MOV AL,BL
- OUT DX,AL {LB der neuen Startadresse setzen}
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,BH {HB der neuen Startadresse setzen}
- OUT DX,AL
- STI
-
- PUSH BX
- PUSH CX
- PUSH SI
- PUSH SI
- CALL CRT.Delay
- POP SI
- POP CX
- POP BX
- LOOP @oneline
-
- END;
- END;
-
- PROCEDURE CopyVRAMtoVRAM(source,dest:POINTER; len:WORD); ASSEMBLER;
- { in: source = Startadresse}
- { dest = Zieladresse }
- { len = Länge des zu kopierenden Bereichs}
- {out: - }
- {rem: Die beiden Bereiche dürfen sich nicht überlappen}
- { Es wird der WriteMode1 verwendet, weshalb die Länge "len" für}
- { je 4 Bytes zählt: bspw. würde ein Aufruf der Form}
- { CopyVRAMtoVRAM(Ptr($A000,0),Ptr($A000,PAGESIZE),PAGESIZE) }
- { eine ganze Seite (4*PAGESIZE = 64000 Bytes) kopieren}
- ASM
- MOV AX,4105h {Writemode1 einschalten}
- MOV DX,3CEh
- OUT DX,AX
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- MOV DX,3C4h
- OUT DX,AX
-
- MOV BX,DS
-
- LES DI,dest
- LDS SI,source
- MOV CX,len
- CLD
- REP MOVSB
-
- MOV DS,BX
-
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- END;
-
-
- PROCEDURE InitRoutines;
- { in: USEEMS = TRUE für: EMS-Speicher für BACKGNDPAGE benutzen}
- {out: SpriteN[],SPRITEAD[],SPRITEPTR[],SPRITESIZE[],BackTile[] wurden auf}
- { "gänzlich leer" initialisiert}
- { NextSprite[] wurde so gesetzt, daß jedes Sprite sein eigener}
- { Nachfolger ist}
- { PAGE, PAGEADR wurden auf die Grafikseite 0 eingestellt}
- { BACKGNDADR wurde auf die Hintergrundseite gesetzt }
- { SCROLLADR wurde auf die scrollbare Hintergrundseite gesetzt}
- { BACKGROUNDMODE wurde auf STATIC gesetzt}
- { Als Defaulttile für den scrollbaren Hintergrund wurde #0 gesetzt }
- { StartVirtualX,StartVirtualY = 0 (d.h.: virtuelle = absolute Koord.)}
- { oldMode = alter Grafikmodus}
- { Error wurde gesetzt, falls keine VGA-Karte im System enthalten ist }
- { CycleTime = 0, d.h.: keine Mindestzeit für einen Animationszyklus }
- { Color = 15, d.h.: weiß }
- { CurrentFont = Zeiger auf internen Font}
- { FontHeight, FontWidth = Abmessungen des internen Fonts}
- { FontType = dessen Typ}
- { ActualColors = Defaultfarbpalette des Modus $13 }
- { CRTAddress = Portadresse des CRT-Adressregisters}
- { StatusReg = Portadresse des Statusregisters }
- { EMSused = TRUE, wenn EMS-Speicher für BACKGNDPAGE alloziert wurde }
- { BackgroundEMSHandle = Handle auf allozierten EMS-Block (wenn EMSused=TRUE)}
- { buf = Zeiger auf allozierten Heap-Block (wenn EMSused=FALSE) }
- { Win* Koordinaten wurden auf das gesamte Animationsfenster gesetzt }
- { SplitIndex wurde so gesetzt, daß alle Sprites auf das Animations- }
- { fenster zurechtgeclipt werden}
- {rem: Diese Prozedur sollte einmal - ganz zu Beginn - zur Initialisierung}
- { des Animationspaketes aufgerufen werden }
- TYPE rec=RECORD lw,hw:WORD END;
- VAR i,adj:WORD;
-
- FUNCTION IsVGA:BOOLEAN;
- BEGIN
- WITH Regs DO
- BEGIN
- AX:=$1A00;
- Intr($10,Regs);
- IsVGA:=(AL=$1A) AND {VGA Identify-Adapter-Function unterstützt?}
- ( (BL=7) OR (BL=8) ) {VGAMono oder VGAColor - Adapter}
- END;
- END;
-
- BEGIN
- IF IsVGA THEN Error:=Err_None
- ELSE BEGIN
- Error:=Err_NoVGA;
- exit
- END;
-
- SetCycleTime(0);
-
- FillChar(SpriteN,SizeOf(SpriteN),0);
- FillChar(SPRITEAD,SizeOf(SPRITEAD),0);
- FillChar(SPRITESIZE,SizeOf(SPRITESIZE),0);
- FillChar(BackTile,SizeOf(BackTile),0);
-
- FOR i:=0 TO LoadMAX DO
- BEGIN
- NextSprite[i]:=i;
- SPRITEPTR[i]:=NIL
- END;
-
- BACKGNDADR:=Segment_Adr[BACKGNDPAGE]; {Segmentadresse der Hintergrundseite}
-
- PAGE:=0; {Seite, auf der gezeichnet werden soll}
- PAGEADR:=Segment_Adr[PAGE];
- SCROLLADR:=Segment_Adr[SCROLLPAGE];
- SetBackgroundMode(STATIC);
- SetOffscreenTile(0);
-
- StartVirtualX:=0; StartVirtualY:=0; {virtuelle = absolute Koordinaten}
- Color:=white; {aktuelle Zeichenfarbe sei Weiß }
- regs.ah:=$f; intr($10,regs); oldMode:=regs.al;
-
- ActualColors:=DefaultColors;
- {SetShadowTab(Schatten) kann entfallen, da Defaultwerte schon gesetzt!}
-
- ASM {ermitteln, ob Farb- oder Monochromdarstellung}
- MOV DX,3CCh {Output-Register befragen:}
- IN AL,DX
- TEST AL,1 {ist es ein Farbbildschirm?}
- MOV DX,3D4h
- JNZ @L1 {ja }
- MOV DX,3B4h {nein}
- @L1: {DX = 3B4h / 3D4h = CRTAddress-Register für monochrom/Farbe}
- MOV CRTAddress,DX
- ADD DX,6 {DX = 3BAh / 3DAh = Status-Register für monochrom/Farbe}
- MOV StatusReg,DX
- END; {of ASM}
-
- LoadFont(''); {internen Font laden}
- SetAnimateWindow(0,0,319,199);
-
- EMSused:=FALSE;
-
- IF EmsInstalled(BACKGNDADR) AND
- EMSIsHardWareEMS AND
- (EMSPagesAvailable>=4) AND
- (EMSError=0)
- THEN BEGIN {EMS verwenden}
- BackgroundEMSHandle:=EMSAllocate(4); {64K allozieren}
- If EmsError<>0
- THEN BEGIN {doch nicht}
- WriteLn ('EMS-Allozierungsfehler!' );
- EMSRelease(BackgroundEMSHandle);
- END
- ELSE BEGIN
- EMSused:=TRUE;
- buf:=Ptr(BACKGNDADR,0)
- END;
- END;
-
- IF NOT EMSused
- THEN BEGIN {kein, nicht genügend oder falscher EMS-Speicher, Heap benutzen:}
- New(buf)
- END
- ELSE EMSFillFrame(BackgroundEMSHandle); {Zugriff auf EMS vorbereiten}
-
- FillChar(buf^,SizeOf(buf^),0);
- adj:=rec(buf).lw DIV 16;
- IF (rec(buf).lw MOD 16)<>0
- THEN inc(adj); {zu aufsteigenden Adressen hin runden}
- inc(rec(buf).hw,adj);
- rec(buf).lw:=0;
-
- IF rec(buf).lw<>0
- THEN BEGIN
- WRITELN('Fehler: buf^ liegt nicht auf Segmentgrenze');
- Halt
- END
- ELSE BEGIN
- Segment_Adr[BACKGNDPAGE]:=rec(buf).hw;
- Offset_Adr[BACKGNDPAGE]:=0;
- BACKGNDADR:=rec(buf).hw
- END;
- SetAnimateWindow(0,0,XMAX,YMAX);
- SetSplitIndex(-1); {=alle clippen}
- END;
-
- PROCEDURE CloseRoutines;
- { in: oldMode = alter Grafikmodus, auf den zurückgeschaltet werden soll}
- { EMSused = wurde EMS-Speicher für BACKGNDPAGE verwendet?}
- { BackgroundEMSHandle = falls ja, so ist dies das Handle darauf}
- { buf = falls nein, dann ist dies der Pointer auf normalen Heap}
- {out: - }
- BEGIN
- regs.al:=oldMode; regs.ah:=0; intr($10,regs);
- IF EMSused
- THEN EMSRelease(BackgroundEMSHandle)
- ELSE Release(buf);
- END;
-
- FUNCTION GetErrorMessage:STRING;
- { in: Error = Nummer des aufgetretenen Fehlers}
- {out: den Fehler in Worten}
- BEGIN
- CASE Error OF
- Err_None:GetErrorMessage:='No Error';
- Err_NotEnoughMemory:GetErrorMessage:='Not enough memory available on heap';
- Err_FileIO:GetErrorMessage:='I/O-error with file';
- Err_InvalidSpriteNumber:GetErrorMessage:='Invalid sprite number used';
- Err_NoSprite:GetErrorMessage:='No (or corrupted) sprite file';
- Err_InvalidPageNumber:GetErrorMessage:='Invalid page number used';
- Err_NoVGA:GetErrorMessage:='No VGA-card found';
- Err_NoPicture:GetErrorMessage:='No (or corrupted) picture file';
- Err_InvalidPercentage:GetErrorMessage:='Percentage value must be 0..100';
- Err_NoTile:GetErrorMessage:='No (or corrupted) tile/sprite file';
- Err_InvalidTileNumber:GetErrorMessage:='Invalid tile number used';
- Err_InvalidCoordinates:GetErrorMessage:='Invalid coordinates used';
- Err_BackgroundToBig:GetErrorMessage:='Background to big for tile-buffer';
- Err_InvalidMode:GetErrorMessage:='Only STATIC or SCROLLING allowed here';
- Err_InvalidSpriteLoadNumber:GetErrorMessage:='Invalid spriteload number used';
- Err_NoPalette:GetErrorMessage:='No (or corrupted) palette file';
- Err_PaletteWontFit:GetErrorMessage:='Attempt to write beyond palette end';
- Err_InvalidFade:GetErrorMessage:='Invalid fade style used';
- Err_NoFont:GetErrorMessage:='No (or corrupted) font file';
- Err_EMSError:GetErrorMessage:='Problems with EMS memory';
- ELSE GetErrorMessage:='Unknown error';
- END;
- END;
-
- FUNCTION FindFile(P:PathStr):PathStr;
- { in: P = zu suchende Datei, mit Anfangspfad}
- {out: vollständiger Pfad zur Datei}
- {rem: Steht die Datei nicht im angegebenen Verzeichnis, so werden alle}
- { rekursiv alle Unterverzeichnisse abgesucht.}
- { Endet die Suche auch dort ergebnislos, so wird '' zurückgegeben}
- VAR D: DirStr;
- N: NameStr;
- E: ExtStr;
- DateiName:STRING[12];
- temp:PathStr;
-
- FUNCTION SearchFile(Pfad:PathStr):PathStr;
- { in: DateiName = zu suchende Datei}
- { Pfad = Anfangssuchpfad für diese Datei}
- {out: vollständiger Pfad zur Datei oder '', falls Datei nicht gefunden}
- VAR Datei,Dir:SearchRec;
- BEGIN
- FindFirst(Pfad+DateiName,AnyFile,Datei);
- WHILE DosError=0 DO
- BEGIN
- IF (Datei.Attr AND Directory)<>Directory
- THEN BEGIN
- SearchFile:=Pfad+Datei.Name;
- Exit
- END;
- FindNext(Datei)
- END;
-
- {hierher, wenn Suche im aktuellen Verzeichnis erfolglos}
- FindFirst(Pfad+'*.*',Directory,Dir);
- WHILE DosError=0 DO
- BEGIN
- IF ((Dir.Attr AND Directory)=Directory) AND (Dir.Name[1]<>'.')
- THEN BEGIN {durchsuche nächstes Directory}
- temp:=SearchFile(Pfad+Dir.Name+'\');
- IF temp<>''
- THEN BEGIN {rekursiv gefunden!}
- SearchFile:=temp;
- Exit
- END;
- END;
- FindNext(Dir);
- END;
- SearchFile:='';
- END;
-
- BEGIN
- FSplit(P,D,N,E);
- DateiName:=N+E;
- FindFile:=SearchFile(D)
- END;
-
-
-
- BEGIN
-
- InitRoutines;
-
- END.
-